PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.87
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.87
51.1.87 51.1.86 51.1.84 51.1.85 51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 All 41 releases
← All changes | includes/extensions/Header_Footer_Builder/Header_Footer_Builder.php +4450 -0 51.1.2 → 51.1.87 View file →
@@ -1,0 +1,4450 @@
1 +<?php /** @noinspection PhpMissingFieldTypeInspection, DuplicatedCode */
2 +
3 +namespace King_Addons;
4 +
5 +use Elementor;
6 +use WP_Query;
7 +
8 +if (!defined('ABSPATH')) {
9 + exit;
10 +}
11 +
12 +final class Header_Footer_Builder
13 +{
14 + private static ?Header_Footer_Builder $instance = null;
15 + private static ?string $current_page_type = null;
16 + private static array $current_page_data = array();
17 + private static $location_selection;
18 + private static $user_selection;
19 + private static $elementor_instance;
20 +
21 + /**
22 + * Admin menu slug for the new page.
23 + *
24 + * @var string
25 + */
26 + private string $menu_slug = 'king-addons-el-hf';
27 +
28 + public static function instance(): ?Header_Footer_Builder
29 + {
30 + if (is_null(self::$instance)) {
31 + self::$instance = new self();
32 + }
33 + return self::$instance;
34 + }
35 +
36 + public function __construct()
37 + {
38 + add_action('init', [$this, 'addPostType']);
39 + add_action('add_meta_boxes', [$this, 'registerMetabox']);
40 + add_action('save_post', [$this, 'saveMetaboxData']);
41 + add_action('template_redirect', [$this, 'checkUserCanEdit']);
42 + add_filter('screen_options_show_screen', [$this, 'disableScreenOptions'], 10, 2);
43 +
44 + require_once(KING_ADDONS_PATH . 'includes/extensions/Header_Footer_Builder/ELHF_Render_On_Canvas.php');
45 + add_filter('single_template', [$this, 'loadElementorCanvasTemplate']);
46 + add_filter('template_include', [$this, 'forceElementorCanvasTemplate'], 99);
47 +
48 + self::setCompatibility();
49 + add_action('admin_enqueue_scripts', array($this, 'enqueueScripts'));
50 + add_action('admin_action_edit', array($this, 'initialize_options'));
51 + add_action('wp_ajax_king_addons_el_hf_get_posts_by_query', array($this, 'king_addons_el_hf_get_posts_by_query'));
52 + add_action('pre_get_posts', [$this, 'forcePreviewQuery']);
53 +
54 + // Handle template creation and actions
55 + add_action('admin_post_ka_hf_builder_create', [$this, 'handleCreateTemplate']);
56 + add_action('admin_post_ka_hf_builder_quick_update', [$this, 'handleQuickUpdate']);
57 +
58 + // AJAX handler for conditions popup
59 + add_action('wp_ajax_ka_hf_save_conditions', [$this, 'handleAjaxSaveConditions']);
60 +
61 + // AJAX handlers for rename and toggle status
62 + add_action('wp_ajax_ka_hf_rename_template', [$this, 'handleAjaxRenameTemplate']);
63 + add_action('wp_ajax_ka_hf_toggle_template_status', [$this, 'handleAjaxToggleTemplateStatus']);
64 +
65 + if (is_admin()) {
66 + add_action('manage_king-addons-el-hf_posts_custom_column', [$this, 'columnContent'], 10, 2);
67 + add_filter('manage_king-addons-el-hf_posts_columns', [$this, 'columnHeadings']);
68 + }
69 + }
70 +
71 + /**
72 + * Register admin menu entry as top-level menu.
73 + *
74 + * @return void
75 + */
76 + public function registerAdminMenu(): void
77 + {
78 + global $menu;
79 + $menu['54.6'] = array('', 'read', 'separator-king-addons-hf', '', 'wp-menu-separator');
80 +
81 + add_menu_page(
82 + esc_html__('Header & Footer Builder', 'king-addons'),
83 + esc_html__('Header & Footer', 'king-addons'),
84 + 'manage_options',
85 + $this->menu_slug,
86 + [$this, 'renderAdminPage'],
87 + 'dashicons-align-full-width',
88 + 54.7
89 + );
90 + }
91 +
92 + /**
93 + * Render modern admin page for Header & Footer Builder.
94 + *
95 + * @return void
96 + */
97 + public function renderAdminPage(): void
98 + {
99 + if (!current_user_can('manage_options')) {
100 + return;
101 + }
102 +
103 + // Include shared dark theme support
104 + include KING_ADDONS_PATH . 'includes/admin/shared/dark-theme.php';
105 +
106 + // Handle tab navigation
107 + $current_tab = isset($_GET['tab']) ? sanitize_key(wp_unslash($_GET['tab'])) : 'templates'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
108 + if (!in_array($current_tab, ['templates', 'settings'], true)) {
109 + $current_tab = 'templates';
110 + }
111 +
112 + $this->handleInlineActions();
113 + $templates = $this->prepareAdminTemplates();
114 +
115 + $base_url = admin_url('admin.php?page=' . $this->menu_slug);
116 + $status_filter = 'all';
117 + $filtered_templates = $templates;
118 +
119 + $type_cards = [
120 + 'header' => [
121 + 'label' => esc_html__('Header', 'king-addons'),
122 + 'desc' => esc_html__('Site header templates', 'king-addons'),
123 + 'value' => 'king_addons_el_hf_type_header',
124 + ],
125 + 'footer' => [
126 + 'label' => esc_html__('Footer', 'king-addons'),
127 + 'desc' => esc_html__('Site footer templates', 'king-addons'),
128 + 'value' => 'king_addons_el_hf_type_footer',
129 + ],
130 + ];
131 +
132 + $this->renderModernStyles();
133 +
134 + // Render dark theme styles and init
135 + ka_render_dark_theme_styles();
136 + ka_render_dark_theme_init();
137 + ?>
138 + <script>
139 + if (document.body) {
140 + document.body.classList.add('ka-admin-v3');
141 + } else {
142 + document.addEventListener('DOMContentLoaded', function() {
143 + document.body.classList.add('ka-admin-v3');
144 + });
145 + }
146 + </script>
147 +
148 + <div class="ka-hf">
149 + <header class="ka-hf-header">
150 + <div class="ka-hf-header-content">
151 + <span class="ka-hf-title-icon" aria-hidden="true">
152 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
153 + <path d="M3 3h18v6H3zM3 15h18v6H3z" />
154 + </svg>
155 + </span>
156 + <div class="ka-hf-header-titles">
157 + <h1><span class="ka-hf-title-text"><?php esc_html_e('Header & Footer Builder', 'king-addons'); ?></span></h1>
158 + <p><?php esc_html_e('Create custom headers and footers with display conditions', 'king-addons'); ?></p>
159 + </div>
160 + </div>
161 + <div class="ka-hf-header-actions">
162 + <?php if ('templates' === $current_tab) : ?>
163 + <button type="button" id="ka-hf-add-new" class="ka-hf-btn ka-hf-btn-primary">
164 + <span class="ka-hf-btn-icon" aria-hidden="true">+</span>
165 + <?php esc_html_e('Add New Template', 'king-addons'); ?>
166 + </button>
167 + <?php endif; ?>
168 + <?php ka_render_dark_theme_toggle(); ?>
169 + </div>
170 + </header>
171 +
172 + <!-- Navigation Tabs -->
173 + <nav class="ka-hf-nav-tabs">
174 + <a href="<?php echo esc_url($base_url); ?>" class="ka-hf-nav-tab<?php echo 'templates' === $current_tab ? ' is-active' : ''; ?>">
175 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
176 + <path d="M3 3h18v6H3zM3 15h18v6H3z" />
177 + </svg>
178 + <?php esc_html_e('Templates', 'king-addons'); ?>
179 + </a>
180 + <a href="<?php echo esc_url(add_query_arg('tab', 'settings', $base_url)); ?>" class="ka-hf-nav-tab<?php echo 'settings' === $current_tab ? ' is-active' : ''; ?>">
181 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
182 + <circle cx="12" cy="12" r="3"/>
183 + <path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/>
184 + </svg>
185 + <?php esc_html_e('Display Settings', 'king-addons'); ?>
186 + </a>
187 + </nav>
188 +
189 + <?php if ('templates' === $current_tab) : ?>
190 +
191 + <div class="ka-hf-types" role="list">
192 + <?php foreach ($type_cards as $type_slug => $data) : ?>
193 + <?php $type_icon_svg = $this->getTypeIconSvg($type_slug); ?>
194 + <button
195 + type="button"
196 + class="ka-hf-type"
197 + role="listitem"
198 + data-ka-hf-type="<?php echo esc_attr($data['value']); ?>"
199 + >
200 + <div class="ka-hf-type-icon" aria-hidden="true">
201 + <?php echo $type_icon_svg; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
202 + </div>
203 + <div class="ka-hf-type-label"><?php echo esc_html($data['label']); ?></div>
204 + <div class="ka-hf-type-desc"><?php echo esc_html($data['desc']); ?></div>
205 + </button>
206 + <?php endforeach; ?>
207 + </div>
208 +
209 + <section class="ka-hf-section">
210 + <div class="ka-hf-section-header">
211 + <h2 class="ka-hf-section-title"><?php esc_html_e('Templates', 'king-addons'); ?></h2>
212 + <div class="ka-hf-section-actions">
213 + <div class="ka-hf-filters" role="navigation">
214 + <button type="button" class="ka-hf-filter is-active" data-filter="all"><?php esc_html_e('All', 'king-addons'); ?></button>
215 + <button type="button" class="ka-hf-filter" data-filter="header"><?php esc_html_e('Headers', 'king-addons'); ?></button>
216 + <button type="button" class="ka-hf-filter" data-filter="footer"><?php esc_html_e('Footers', 'king-addons'); ?></button>
217 + </div>
218 + <div class="ka-hf-section-count"><?php echo esc_html(count($filtered_templates) . ' ' . _n('item', 'items', count($filtered_templates), 'king-addons')); ?></div>
219 + </div>
220 + </div>
221 +
222 + <div class="ka-hf-templates" role="list">
223 + <?php if (empty($filtered_templates)) : ?>
224 + <div class="ka-hf-empty">
225 + <h3 class="ka-hf-empty-title"><?php esc_html_e('No templates yet', 'king-addons'); ?></h3>
226 + <p class="ka-hf-empty-desc"><?php esc_html_e('Create your first header or footer template to get started.', 'king-addons'); ?></p>
227 + <button type="button" class="ka-hf-btn ka-hf-btn-primary" id="ka-hf-add-new-empty">
228 + <span class="ka-hf-btn-icon" aria-hidden="true">+</span>
229 + <?php esc_html_e('Add New Template', 'king-addons'); ?>
230 + </button>
231 + </div>
232 + <?php else : ?>
233 + <?php foreach ($filtered_templates as $template) : ?>
234 + <?php
235 + $template_id = (int) ($template['id'] ?? 0);
236 + if (!$template_id) {
237 + continue;
238 + }
239 +
240 + $title = !empty($template['title']) ? (string) $template['title'] : sprintf(
241 + esc_html__('Template #%d', 'king-addons'),
242 + $template_id
243 + );
244 +
245 + $edit_elementor_url = admin_url('post.php?post=' . $template_id . '&action=elementor');
246 + $edit_settings_url = admin_url('post.php?post=' . $template_id . '&action=edit');
247 + $type_value = $template['type'] ?? '';
248 + $type_label = 'king_addons_el_hf_type_header' === $type_value ? esc_html__('Header', 'king-addons') : ('king_addons_el_hf_type_footer' === $type_value ? esc_html__('Footer', 'king-addons') : esc_html__('Not Set', 'king-addons'));
249 + $type_slug = 'king_addons_el_hf_type_header' === $type_value ? 'header' : ('king_addons_el_hf_type_footer' === $type_value ? 'footer' : 'unset');
250 + $delete_url = wp_nonce_url(add_query_arg(['action' => 'delete_template', 'template_id' => $template_id], $base_url), 'ka_hf_delete_' . $template_id);
251 + $conditions_text = $this->summarizeConditions($template);
252 + $title_icon_svg = $this->getTypeIconSvg($type_slug);
253 + $post_status = get_post_status($template_id);
254 + $is_disabled = 'publish' !== $post_status;
255 + $status_label = $is_disabled ? esc_html__('Disabled', 'king-addons') : $type_label;
256 + ?>
257 + <div class="ka-hf-template" role="listitem" data-template-type="<?php echo esc_attr($type_slug); ?>" data-template-id="<?php echo esc_attr($template_id); ?>" data-status="<?php echo esc_attr($post_status); ?>" data-type-label="<?php echo esc_attr($type_label); ?>">
258 + <div class="ka-hf-template-status <?php echo $is_disabled ? 'is-disabled' : 'is-enabled'; ?>">
259 + <?php echo esc_html($status_label); ?>
260 + </div>
261 + <div class="ka-hf-template-info">
262 + <a class="ka-hf-template-title" href="<?php echo esc_url($edit_elementor_url); ?>">
263 + <span class="ka-hf-template-title-icon" aria-hidden="true">
264 + <?php echo $title_icon_svg; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
265 + </span>
266 + <span class="ka-hf-template-title-text"><?php echo esc_html($title); ?></span>
267 + </a>
268 + <div class="ka-hf-template-meta">
269 + <span class="ka-hf-template-type"><?php echo esc_html($type_label); ?></span>
270 + </div>
271 + </div>
272 + <?php
273 + // Prepare conditions data for the popup
274 + $include_locs = $template['include_locations'] ?? [];
275 + $exclude_locs = $template['exclude_locations'] ?? [];
276 + $user_roles_arr = $template['user_roles'] ?? [];
277 + $template_data = [
278 + 'id' => $template_id,
279 + 'title' => $title,
280 + 'type' => $type_value,
281 + 'include' => $include_locs,
282 + 'exclude' => $exclude_locs,
283 + 'userRoles' => $user_roles_arr,
284 + ];
285 + ?>
286 + <button type="button" class="ka-hf-template-condition ka-hf-open-conditions" title="<?php echo esc_attr__('Edit Display Conditions', 'king-addons'); ?>" data-template='<?php echo esc_attr(wp_json_encode($template_data)); ?>'>
287 + <svg class="ka-hf-condition-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
288 + <circle cx="12" cy="12" r="3"/>
289 + <path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/>
290 + </svg>
291 + <?php echo esc_html($conditions_text); ?>
292 + </button>
293 + <div class="ka-hf-template-actions">
294 + <a class="ka-hf-btn ka-hf-btn-primary" href="<?php echo esc_url($edit_elementor_url); ?>"><?php esc_html_e('Edit with Elementor', 'king-addons'); ?></a>
295 + <div class="ka-hf-dropdown" data-ka-dropdown>
296 + <button type="button" class="ka-hf-dropdown-trigger" aria-label="<?php echo esc_attr(esc_html__('More actions', 'king-addons')); ?>">
297 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
298 + <circle cx="12" cy="5" r="1" />
299 + <circle cx="12" cy="12" r="1" />
300 + <circle cx="12" cy="19" r="1" />
301 + </svg>
302 + </button>
303 + <div class="ka-hf-dropdown-menu" role="menu">
304 + <button type="button" class="ka-hf-dropdown-item ka-hf-rename-btn" role="menuitem" data-id="<?php echo esc_attr($template_id); ?>" data-title="<?php echo esc_attr($title); ?>">
305 + <?php esc_html_e('Rename', 'king-addons'); ?>
306 + </button>
307 + <a class="ka-hf-dropdown-item" role="menuitem" href="<?php echo esc_url($edit_settings_url); ?>">
308 + <?php esc_html_e('WP Edit', 'king-addons'); ?>
309 + </a>
310 + <button type="button" class="ka-hf-dropdown-item ka-hf-toggle-status-btn" role="menuitem" data-id="<?php echo esc_attr($template_id); ?>" data-status="<?php echo esc_attr(get_post_status($template_id)); ?>">
311 + <?php echo get_post_status($template_id) === 'publish' ? esc_html__('Disable', 'king-addons') : esc_html__('Enable', 'king-addons'); ?>
312 + </button>
313 + <a class="ka-hf-dropdown-item is-danger" role="menuitem" href="<?php echo esc_url($delete_url); ?>" onclick="return confirm('<?php echo esc_js(esc_html__('Move template to trash?', 'king-addons')); ?>');">
314 + <?php esc_html_e('Delete', 'king-addons'); ?>
315 + </a>
316 + </div>
317 + </div>
318 + </div>
319 + </div>
320 + <?php endforeach; ?>
321 + <?php endif; ?>
322 + </div>
323 +
324 + <div class="ka-hf-filter-empty" style="display: none;">
325 + <h3 class="ka-hf-empty-title"><?php esc_html_e('No templates found', 'king-addons'); ?></h3>
326 + <p class="ka-hf-empty-desc"><?php esc_html_e('Try a different filter or create a new template.', 'king-addons'); ?></p>
327 + <button type="button" class="ka-hf-btn ka-hf-btn-primary" id="ka-hf-add-new-filter-empty">
328 + <span class="ka-hf-btn-icon" aria-hidden="true">+</span>
329 + <?php esc_html_e('Add New Template', 'king-addons'); ?>
330 + </button>
331 + </div>
332 + </section>
333 +
334 + <?php $this->renderAddNewModal(); ?>
335 + <?php $this->renderRenameModal(); ?>
336 + <?php $this->renderConditionsPopup(); ?>
337 +
338 + <?php else : // settings tab ?>
339 +
340 + <?php $this->renderDisplaySettingsTab(); ?>
341 +
342 + <?php endif; ?>
343 + </div>
344 + <?php
345 +
346 + // Render dark theme script at the end
347 + ka_render_dark_theme_script();
348 + }
349 +
350 + /**
351 + * Render the Display Settings tab content.
352 + *
353 + * @return void
354 + */
355 + private function renderDisplaySettingsTab(): void
356 + {
357 + $chosen_option = get_option('king_addons_el_hf_compatibility_option', '3');
358 + ?>
359 + <section class="ka-hf-section ka-hf-settings-section">
360 + <div class="ka-hf-section-header">
361 + <h2 class="ka-hf-section-title"><?php esc_html_e('Display Settings', 'king-addons'); ?></h2>
362 + </div>
363 +
364 + <form method="post" action="options.php" class="ka-hf-settings-form">
365 + <?php settings_fields('king-addons-el-hf-ext-options'); ?>
366 +
367 + <div class="ka-hf-settings-card">
368 + <h3 class="ka-hf-settings-card-title"><?php esc_html_e('Compatibility Mode', 'king-addons'); ?></h3>
369 + <p class="ka-hf-settings-card-desc"><?php esc_html_e('To ensure compatibility with the current theme, three methods are available:', 'king-addons'); ?></p>
370 +
371 + <div class="ka-hf-settings-options">
372 +
373 + <label class="ka-hf-settings-option">
374 + <input type="radio" name="king_addons_el_hf_compatibility_option" value="1" <?php checked($chosen_option, '1'); ?>>
375 + <div class="ka-hf-settings-option-content">
376 + <span class="ka-hf-settings-option-title"><?php esc_html_e('Method 1 - Replace Theme Templates', 'king-addons'); ?></span>
377 + <span class="ka-hf-settings-option-desc"><?php esc_html_e('This method replaces the theme header (header.php) and footer (footer.php) templates with custom templates. Works well with classic themes that use standard WordPress template structure.', 'king-addons'); ?></span>
378 + </div>
379 + </label>
380 +
381 + <label class="ka-hf-settings-option">
382 + <input type="radio" name="king_addons_el_hf_compatibility_option" value="2" <?php checked($chosen_option, '2'); ?>>
383 + <div class="ka-hf-settings-option-content">
384 + <span class="ka-hf-settings-option-title"><?php esc_html_e('Method 2 - CSS Hide + Inject', 'king-addons'); ?></span>
385 + <span class="ka-hf-settings-option-desc"><?php esc_html_e('This method hides the theme header and footer using CSS (display: none;) and injects custom templates via wp_body_open and wp_footer hooks.', 'king-addons'); ?></span>
386 + </div>
387 + </label>
388 +
389 + <label class="ka-hf-settings-option">
390 + <input type="radio" name="king_addons_el_hf_compatibility_option" value="3" <?php checked($chosen_option, '3'); ?>>
391 + <div class="ka-hf-settings-option-content">
392 + <span class="ka-hf-settings-option-title"><?php esc_html_e('Method 3 - Universal (Recommended)', 'king-addons'); ?></span>
393 + <span class="ka-hf-settings-option-desc"><?php esc_html_e('This method combines multiple approaches for maximum theme compatibility. It uses hooks, output buffering, CSS hiding of native theme headers/footers, and JavaScript fallback to ensure headers and footers display correctly on all themes including Block Themes (FSE).', 'king-addons'); ?></span>
394 + </div>
395 + </label>
396 +
397 + </div>
398 +
399 + <div class="ka-hf-settings-actions">
400 + <button type="submit" class="ka-hf-btn ka-hf-btn-primary"><?php esc_html_e('Save Settings', 'king-addons'); ?></button>
401 + </div>
402 + </div>
403 + </form>
404 + </section>
405 + <?php
406 + }
407 +
408 + /**
409 + * Render the Add New Template modal.
410 + *
411 + * @return void
412 + */
413 + private function renderAddNewModal(): void
414 + {
415 + self::$location_selection = self::getLocationSelections();
416 + self::$user_selection = self::get_user_selections();
417 + ?>
418 + <div id="ka-hf-modal" class="ka-hf-modal-overlay" aria-hidden="true">
419 + <div class="ka-hf-modal" role="dialog" aria-modal="true" aria-labelledby="ka-hf-create-title">
420 + <h3 id="ka-hf-create-title"><?php echo esc_html__('Create Header / Footer Template', 'king-addons'); ?></h3>
421 + <p class="ka-hf-modal-desc"><?php echo esc_html__('Choose the template type and configure display conditions.', 'king-addons'); ?></p>
422 +
423 + <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
424 + <input type="hidden" name="action" value="ka_hf_builder_create" />
425 + <?php wp_nonce_field('ka_hf_builder_create', 'ka_hf_builder_create_nonce'); ?>
426 +
427 + <div class="ka-hf-form-group">
428 + <label class="ka-hf-form-label" for="ka-hf-title"><?php echo esc_html__('Template Name', 'king-addons'); ?></label>
429 + <input type="text" id="ka-hf-title" name="ka_hf_title" class="ka-hf-modal-input" value="<?php echo esc_attr__('My Template', 'king-addons'); ?>" />
430 + </div>
431 +
432 + <div class="ka-hf-form-group">
433 + <label class="ka-hf-form-label" for="ka-hf-type"><?php echo esc_html__('Template Type', 'king-addons'); ?></label>
434 + <select id="ka-hf-type" name="ka_hf_type" class="ka-hf-form-select">
435 + <option value="king_addons_el_hf_type_header"><?php echo esc_html__('Header', 'king-addons'); ?></option>
436 + <option value="king_addons_el_hf_type_footer"><?php echo esc_html__('Footer', 'king-addons'); ?></option>
437 + </select>
438 + </div>
439 +
440 + <div class="ka-hf-form-group">
441 + <label class="ka-hf-form-label"><?php echo esc_html__('Display On', 'king-addons'); ?></label>
442 + <p class="ka-hf-form-desc"><?php echo esc_html__('Add locations where this template should appear', 'king-addons'); ?></p>
443 + <div class="ka-hf-conditions-wrap">
444 + <div class="ka-hf-create-rule-row">
445 + <select id="ka-hf-display-rule" name="ka_hf_display_rule" class="ka-hf-form-select">
446 + <?php foreach (self::$location_selection as $group_data) : ?>
447 + <optgroup label="<?php echo esc_attr($group_data['label']); ?>">
448 + <?php foreach ($group_data['value'] as $opt_key => $opt_value) : ?>
449 + <option value="<?php echo esc_attr($opt_key); ?>" <?php selected($opt_key, 'basic-global'); ?>><?php echo esc_html($opt_value); ?></option>
450 + <?php endforeach; ?>
451 + </optgroup>
452 + <?php endforeach; ?>
453 + </select>
454 + <input type="text" id="ka-hf-display-specific" name="ka_hf_display_specific" class="ka-hf-modal-input ka-hf-specific-input" placeholder="<?php echo esc_attr__('Enter page/post IDs (comma separated)', 'king-addons'); ?>" style="display: none;" />
455 + </div>
456 + </div>
457 + </div>
458 +
459 + <div class="ka-hf-form-group">
460 + <label class="ka-hf-form-label"><?php echo esc_html__('User Roles (Optional)', 'king-addons'); ?></label>
461 + <p class="ka-hf-form-desc"><?php echo esc_html__('Display template for specific user roles.', 'king-addons'); ?></p>
462 + <div id="ka-hf-create-user-roles" class="ka-hf-rules-container">
463 + <!-- Role rows will be added dynamically via JS -->
464 + </div>
465 + <button type="button" class="ka-hf-add-rule-btn" id="ka-hf-create-add-user-role">
466 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M12 5v14M5 12h14"/></svg>
467 + <?php echo esc_html__('Add User Role', 'king-addons'); ?>
468 + </button>
469 + </div>
470 +
471 + <div class="ka-hf-form-group">
472 + <label class="ka-hf-form-label">
473 + <input type="checkbox" id="ka-hf-display-canvas" name="ka_hf_display_canvas" value="1" />
474 + <?php echo esc_html__('Enable for Elementor Canvas Template', 'king-addons'); ?>
475 + </label>
476 + <p class="ka-hf-form-desc"><?php echo esc_html__('Show this template on pages using Elementor Canvas Template', 'king-addons'); ?></p>
477 + </div>
478 +
479 + <div class="ka-hf-modal-actions">
480 + <button type="button" class="ka-hf-btn ka-hf-btn-secondary ka-hf-modal-close"><?php echo esc_html__('Cancel', 'king-addons'); ?></button>
481 + <button type="submit" class="ka-hf-btn ka-hf-btn-primary"><?php echo esc_html__('Create and Edit with Elementor', 'king-addons'); ?></button>
482 + </div>
483 + </form>
484 + </div>
485 + </div>
486 + <?php
487 + }
488 +
489 + /**
490 + * Render the Rename Template modal.
491 + *
492 + * @return void
493 + */
494 + private function renderRenameModal(): void
495 + {
496 + ?>
497 + <div id="ka-hf-rename-modal" class="ka-hf-modal-overlay" aria-hidden="true">
498 + <div class="ka-hf-modal" role="dialog" aria-modal="true" aria-labelledby="ka-hf-rename-title">
499 + <h3 id="ka-hf-rename-title"><?php echo esc_html__('Rename Template', 'king-addons'); ?></h3>
500 + <p class="ka-hf-modal-desc"><?php echo esc_html__('Enter a new name for this template.', 'king-addons'); ?></p>
501 +
502 + <input type="hidden" id="ka-hf-rename-id" value="" />
503 + <div class="ka-hf-form-group">
504 + <label class="ka-hf-form-label" for="ka-hf-rename-title-input"><?php echo esc_html__('Template Name', 'king-addons'); ?></label>
505 + <input type="text" id="ka-hf-rename-title-input" class="ka-hf-modal-input" value="" />
506 + </div>
507 +
508 + <div class="ka-hf-modal-actions">
509 + <button type="button" class="ka-hf-btn ka-hf-btn-secondary ka-hf-rename-close"><?php echo esc_html__('Cancel', 'king-addons'); ?></button>
510 + <button type="button" class="ka-hf-btn ka-hf-btn-primary" id="ka-hf-rename-save"><?php echo esc_html__('Save', 'king-addons'); ?></button>
511 + </div>
512 + </div>
513 + </div>
514 + <?php
515 + }
516 +
517 + /**
518 + * Render the Conditions Popup for editing existing templates.
519 + *
520 + * @return void
521 + */
522 + private function renderConditionsPopup(): void
523 + {
524 + self::$location_selection = self::getLocationSelections();
525 + self::$user_selection = self::get_user_selections();
526 +
527 + // Prepare location options JSON for JS
528 + $location_options = [];
529 + foreach (self::$location_selection as $group_key => $group_data) {
530 + foreach ($group_data['value'] as $opt_key => $opt_value) {
531 + $location_options[$opt_key] = $opt_value;
532 + }
533 + }
534 +
535 + $user_options = [];
536 + foreach (self::$user_selection as $group_data) {
537 + foreach ($group_data['value'] as $opt_key => $opt_value) {
538 + $user_options[$opt_key] = $opt_value;
539 + }
540 + }
541 + ?>
542 + <div id="ka-hf-conditions-modal" class="ka-hf-modal-overlay" aria-hidden="true">
543 + <div class="ka-hf-modal ka-hf-modal-conditions" role="dialog" aria-modal="true" aria-labelledby="ka-hf-conditions-title">
544 + <h3 id="ka-hf-conditions-title"><?php echo esc_html__('Template Settings', 'king-addons'); ?></h3>
545 + <p class="ka-hf-modal-desc"><?php echo esc_html__('Configure template type and display conditions.', 'king-addons'); ?></p>
546 +
547 + <input type="hidden" id="ka-hf-cond-template-id" value="" />
548 +
549 + <!-- Template Type Section -->
550 + <div class="ka-hf-form-group">
551 + <label class="ka-hf-form-label"><?php echo esc_html__('Template Type', 'king-addons'); ?></label>
552 + <select id="ka-hf-cond-template-type" class="ka-hf-form-select">
553 + <option value="king_addons_el_hf_type_header"><?php echo esc_html__('Header', 'king-addons'); ?></option>
554 + <option value="king_addons_el_hf_type_footer"><?php echo esc_html__('Footer', 'king-addons'); ?></option>
555 + </select>
556 + </div>
557 +
558 + <!-- Include Rules Section -->
559 + <div class="ka-hf-form-group">
560 + <label class="ka-hf-form-label"><?php echo esc_html__('Display On', 'king-addons'); ?></label>
561 + <div id="ka-hf-include-rules" class="ka-hf-rules-container">
562 + <!-- Rules will be added dynamically via JS -->
563 + </div>
564 + <button type="button" class="ka-hf-add-rule-btn" data-rule-type="include">
565 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M12 5v14M5 12h14"/></svg>
566 + <?php echo esc_html__('Add Display Rule', 'king-addons'); ?>
567 + </button>
568 + </div>
569 +
570 + <!-- Exclude Rules Section -->
571 + <div class="ka-hf-form-group">
572 + <label class="ka-hf-form-label"><?php echo esc_html__('Do Not Display On', 'king-addons'); ?></label>
573 + <div id="ka-hf-exclude-rules" class="ka-hf-rules-container">
574 + <!-- Exclusion rules will be added dynamically via JS -->
575 + </div>
576 + <button type="button" class="ka-hf-add-rule-btn" data-rule-type="exclude">
577 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M12 5v14M5 12h14"/></svg>
578 + <?php echo esc_html__('Add Exclusion Rule', 'king-addons'); ?>
579 + </button>
580 + </div>
581 +
582 + <!-- User Roles Section -->
583 + <div class="ka-hf-form-group">
584 + <label class="ka-hf-form-label"><?php echo esc_html__('User Roles (Optional)', 'king-addons'); ?></label>
585 + <div id="ka-hf-user-roles" class="ka-hf-rules-container">
586 + <!-- User role rows will be added dynamically via JS -->
587 + </div>
588 + <button type="button" class="ka-hf-add-rule-btn" id="ka-hf-add-user-role">
589 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M12 5v14M5 12h14"/></svg>
590 + <?php echo esc_html__('Add User Role', 'king-addons'); ?>
591 + </button>
592 + </div>
593 +
594 + <div class="ka-hf-modal-actions">
595 + <button type="button" class="ka-hf-btn ka-hf-btn-secondary ka-hf-conditions-close"><?php echo esc_html__('Cancel', 'king-addons'); ?></button>
596 + <button type="button" id="ka-hf-save-conditions" class="ka-hf-btn ka-hf-btn-primary"><?php echo esc_html__('Save Conditions', 'king-addons'); ?></button>
597 + </div>
598 +
599 + <div id="ka-hf-conditions-saving" class="ka-hf-saving-overlay" style="display: none;">
600 + <span class="ka-hf-spinner"></span>
601 + <?php echo esc_html__('Saving...', 'king-addons'); ?>
602 + </div>
603 + </div>
604 + </div>
605 +
606 + <!-- Rule template for JS cloning -->
607 + <template id="ka-hf-rule-template">
608 + <div class="ka-hf-rule-row">
609 + <select class="ka-hf-form-select ka-hf-rule-select">
610 + <?php foreach (self::$location_selection as $group_data) : ?>
611 + <optgroup label="<?php echo esc_attr($group_data['label']); ?>">
612 + <?php foreach ($group_data['value'] as $opt_key => $opt_value) : ?>
613 + <option value="<?php echo esc_attr($opt_key); ?>"><?php echo esc_html($opt_value); ?></option>
614 + <?php endforeach; ?>
615 + </optgroup>
616 + <?php endforeach; ?>
617 + </select>
618 + <input type="text" class="ka-hf-modal-input ka-hf-specific-input" placeholder="<?php echo esc_attr__('Specific IDs (comma separated)', 'king-addons'); ?>" style="display: none;" />
619 + <button type="button" class="ka-hf-remove-rule-btn" title="<?php echo esc_attr__('Remove rule', 'king-addons'); ?>">
620 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M18 6L6 18M6 6l12 12"/></svg>
621 + </button>
622 + </div>
623 + </template>
624 +
625 + <!-- User role template for JS cloning -->
626 + <template id="ka-hf-user-role-template">
627 + <div class="ka-hf-rule-row ka-hf-user-role-row">
628 + <select class="ka-hf-form-select ka-hf-user-role-select">
629 + <?php foreach (self::$user_selection as $group_data) : ?>
630 + <optgroup label="<?php echo esc_attr($group_data['label']); ?>">
631 + <?php foreach ($group_data['value'] as $opt_key => $opt_value) : ?>
632 + <option value="<?php echo esc_attr($opt_key); ?>"><?php echo esc_html($opt_value); ?></option>
633 + <?php endforeach; ?>
634 + </optgroup>
635 + <?php endforeach; ?>
636 + </select>
637 + <button type="button" class="ka-hf-remove-rule-btn" title="<?php echo esc_attr__('Remove role', 'king-addons'); ?>">
638 + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M18 6L6 18M6 6l12 12"/></svg>
639 + </button>
640 + </div>
641 + </template>
642 +
643 + <script>
644 + var kaHfLocationOptions = <?php echo wp_json_encode($location_options); ?>;
645 + var kaHfUserOptions = <?php echo wp_json_encode($user_options); ?>;
646 + var kaHfAjaxUrl = <?php echo wp_json_encode(admin_url('admin-ajax.php')); ?>;
647 + var kaHfNonce = <?php echo wp_json_encode(wp_create_nonce('ka_hf_save_conditions')); ?>;
648 + </script>
649 + <?php
650 + }
651 +
652 + /**
653 + * AJAX handler to save conditions for a template.
654 + *
655 + * @return void
656 + */
657 + public function handleAjaxSaveConditions(): void
658 + {
659 + if (!current_user_can('manage_options')) {
660 + wp_send_json_error(['message' => esc_html__('Permission denied.', 'king-addons')]);
661 + }
662 +
663 + if (!check_ajax_referer('ka_hf_save_conditions', 'nonce', false)) {
664 + wp_send_json_error(['message' => esc_html__('Invalid nonce.', 'king-addons')]);
665 + }
666 +
667 + $template_id = isset($_POST['template_id']) ? (int) $_POST['template_id'] : 0;
668 + if (!$template_id || 'king-addons-el-hf' !== get_post_type($template_id)) {
669 + wp_send_json_error(['message' => esc_html__('Invalid template.', 'king-addons')]);
670 + }
671 +
672 + // Parse include rules
673 + $include_rules = [];
674 + $include_specific = [];
675 + if (!empty($_POST['include_rules']) && is_array($_POST['include_rules'])) {
676 + foreach ($_POST['include_rules'] as $rule) {
677 + $rule_val = sanitize_text_field(wp_unslash($rule['rule'] ?? ''));
678 + if ($rule_val) {
679 + $include_rules[] = $rule_val;
680 + if ('specifics' === $rule_val && !empty($rule['specific'])) {
681 + $specific_ids = array_map('intval', array_filter(explode(',', sanitize_text_field(wp_unslash($rule['specific'])))));
682 + $include_specific = array_merge($include_specific, $specific_ids);
683 + }
684 + }
685 + }
686 + }
687 +
688 + // Parse exclude rules
689 + $exclude_rules = [];
690 + $exclude_specific = [];
691 + if (!empty($_POST['exclude_rules']) && is_array($_POST['exclude_rules'])) {
692 + foreach ($_POST['exclude_rules'] as $rule) {
693 + $rule_val = sanitize_text_field(wp_unslash($rule['rule'] ?? ''));
694 + if ($rule_val) {
695 + $exclude_rules[] = $rule_val;
696 + if ('specifics' === $rule_val && !empty($rule['specific'])) {
697 + $specific_ids = array_map('intval', array_filter(explode(',', sanitize_text_field(wp_unslash($rule['specific'])))));
698 + $exclude_specific = array_merge($exclude_specific, $specific_ids);
699 + }
700 + }
701 + }
702 + }
703 +
704 + // Parse user roles (multiple)
705 + $user_roles = [];
706 + if (!empty($_POST['user_roles']) && is_array($_POST['user_roles'])) {
707 + foreach ($_POST['user_roles'] as $role) {
708 + $role_val = sanitize_text_field(wp_unslash($role));
709 + if ($role_val) {
710 + $user_roles[] = $role_val;
711 + }
712 + }
713 + }
714 + if (empty($user_roles)) {
715 + $user_roles = ['all'];
716 + }
717 + $user_roles = array_values(array_unique($user_roles));
718 + if (in_array('all', $user_roles, true)) {
719 + $user_roles = ['all'];
720 + }
721 +
722 + // Parse template type
723 + $template_type = isset($_POST['template_type']) ? sanitize_text_field(wp_unslash($_POST['template_type'])) : '';
724 + if (!empty($template_type) && in_array($template_type, ['king_addons_el_hf_type_header', 'king_addons_el_hf_type_footer'], true)) {
725 + update_post_meta($template_id, 'king_addons_el_hf_template_type', $template_type);
726 + }
727 +
728 + // Save meta
729 + $include_locations = [
730 + 'rule' => $include_rules,
731 + 'specific' => $include_specific,
732 + ];
733 + $exclude_locations = [
734 + 'rule' => $exclude_rules,
735 + 'specific' => $exclude_specific,
736 + ];
737 +
738 + update_post_meta($template_id, 'king_addons_el_hf_target_include_locations', $include_locations);
739 + update_post_meta($template_id, 'king_addons_el_hf_target_exclude_locations', $exclude_locations);
740 + update_post_meta($template_id, 'king_addons_el_hf_target_user_roles', $user_roles);
741 +
742 + wp_send_json_success(['message' => esc_html__('Settings saved successfully.', 'king-addons')]);
743 + }
744 +
745 + /**
746 + * AJAX handler to rename a template.
747 + *
748 + * @return void
749 + */
750 + public function handleAjaxRenameTemplate(): void
751 + {
752 + if (!current_user_can('manage_options')) {
753 + wp_send_json_error(['message' => esc_html__('Permission denied.', 'king-addons')]);
754 + }
755 +
756 + if (!check_ajax_referer('ka_hf_save_conditions', 'nonce', false)) {
757 + wp_send_json_error(['message' => esc_html__('Invalid nonce.', 'king-addons')]);
758 + }
759 +
760 + $template_id = isset($_POST['template_id']) ? (int) $_POST['template_id'] : 0;
761 + $new_title = isset($_POST['new_title']) ? sanitize_text_field(wp_unslash($_POST['new_title'])) : '';
762 +
763 + if (!$template_id || 'king-addons-el-hf' !== get_post_type($template_id)) {
764 + wp_send_json_error(['message' => esc_html__('Invalid template.', 'king-addons')]);
765 + }
766 +
767 + if (empty($new_title)) {
768 + wp_send_json_error(['message' => esc_html__('Title cannot be empty.', 'king-addons')]);
769 + }
770 +
771 + $result = wp_update_post([
772 + 'ID' => $template_id,
773 + 'post_title' => $new_title,
774 + ]);
775 +
776 + if (is_wp_error($result)) {
777 + wp_send_json_error(['message' => esc_html__('Failed to rename template.', 'king-addons')]);
778 + }
779 +
780 + wp_send_json_success(['message' => esc_html__('Template renamed successfully.', 'king-addons')]);
781 + }
782 +
783 + /**
784 + * AJAX handler to toggle template status (publish/draft).
785 + *
786 + * @return void
787 + */
788 + public function handleAjaxToggleTemplateStatus(): void
789 + {
790 + if (!current_user_can('manage_options')) {
791 + wp_send_json_error(['message' => esc_html__('Permission denied.', 'king-addons')]);
792 + }
793 +
794 + if (!check_ajax_referer('ka_hf_save_conditions', 'nonce', false)) {
795 + wp_send_json_error(['message' => esc_html__('Invalid nonce.', 'king-addons')]);
796 + }
797 +
798 + $template_id = isset($_POST['template_id']) ? (int) $_POST['template_id'] : 0;
799 + $new_status = isset($_POST['new_status']) ? sanitize_text_field(wp_unslash($_POST['new_status'])) : '';
800 +
801 + if (!$template_id || 'king-addons-el-hf' !== get_post_type($template_id)) {
802 + wp_send_json_error(['message' => esc_html__('Invalid template.', 'king-addons')]);
803 + }
804 +
805 + if (!in_array($new_status, ['publish', 'draft'], true)) {
806 + wp_send_json_error(['message' => esc_html__('Invalid status.', 'king-addons')]);
807 + }
808 +
809 + $result = wp_update_post([
810 + 'ID' => $template_id,
811 + 'post_status' => $new_status,
812 + ]);
813 +
814 + if (is_wp_error($result)) {
815 + wp_send_json_error(['message' => esc_html__('Failed to update template status.', 'king-addons')]);
816 + }
817 +
818 + wp_send_json_success(['message' => esc_html__('Template status updated.', 'king-addons')]);
819 + }
820 +
821 + /**
822 + * Handle "Add New" template submission.
823 + *
824 + * @return void
825 + */
826 + public function handleCreateTemplate(): void
827 + {
828 + if (!current_user_can('manage_options')) {
829 + wp_die(esc_html__('You do not have permission to perform this action.', 'king-addons'));
830 + }
831 +
832 + if (!isset($_POST['ka_hf_builder_create_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['ka_hf_builder_create_nonce'])), 'ka_hf_builder_create')) {
833 + wp_die(esc_html__('Invalid nonce.', 'king-addons'));
834 + }
835 +
836 + $title = isset($_POST['ka_hf_title']) ? sanitize_text_field(wp_unslash($_POST['ka_hf_title'])) : esc_html__('My Template', 'king-addons');
837 + $type = isset($_POST['ka_hf_type']) ? sanitize_text_field(wp_unslash($_POST['ka_hf_type'])) : 'king_addons_el_hf_type_header';
838 + $display_rule = isset($_POST['ka_hf_display_rule']) ? sanitize_text_field(wp_unslash($_POST['ka_hf_display_rule'])) : 'basic-global';
839 + $display_specific = isset($_POST['ka_hf_display_specific']) ? sanitize_text_field(wp_unslash($_POST['ka_hf_display_specific'])) : '';
840 + $display_canvas = isset($_POST['ka_hf_display_canvas']) ? '1' : '';
841 +
842 + // Parse user roles (multiple selection)
843 + $user_roles = [];
844 + if (!empty($_POST['ka_hf_user_role']) && is_array($_POST['ka_hf_user_role'])) {
845 + foreach ($_POST['ka_hf_user_role'] as $role) {
846 + $role_val = sanitize_text_field(wp_unslash($role));
847 + if ($role_val) {
848 + $user_roles[] = $role_val;
849 + }
850 + }
851 + }
852 + if (empty($user_roles)) {
853 + $user_roles = ['all'];
854 + }
855 + $user_roles = array_values(array_unique($user_roles));
856 + if (in_array('all', $user_roles, true)) {
857 + $user_roles = ['all'];
858 + }
859 +
860 + // Validate type
861 + if (!in_array($type, ['king_addons_el_hf_type_header', 'king_addons_el_hf_type_footer'], true)) {
862 + $type = 'king_addons_el_hf_type_header';
863 + }
864 +
865 + // Create the post
866 + $post_id = wp_insert_post([
867 + 'post_type' => 'king-addons-el-hf',
868 + 'post_status' => 'publish',
869 + 'post_title' => $title,
870 + ]);
871 +
872 + if (is_wp_error($post_id)) {
873 + wp_die(esc_html__('Unable to create template.', 'king-addons'));
874 + }
875 +
876 + // Save template type immediately
877 + update_post_meta($post_id, 'king_addons_el_hf_template_type', $type);
878 +
879 + // Save display conditions
880 + $specific_ids = [];
881 + if ('specifics' === $display_rule && !empty($display_specific)) {
882 + $specific_ids = array_map('intval', array_filter(explode(',', $display_specific)));
883 + }
884 + $target_locations = [
885 + 'rule' => [$display_rule],
886 + 'specific' => $specific_ids,
887 + ];
888 + update_post_meta($post_id, 'king_addons_el_hf_target_include_locations', $target_locations);
889 + update_post_meta($post_id, 'king_addons_el_hf_target_exclude_locations', []);
890 +
891 + // Save user roles (multiple)
892 + update_post_meta($post_id, 'king_addons_el_hf_target_user_roles', $user_roles);
893 +
894 + // Save canvas display option
895 + if ($display_canvas) {
896 + update_post_meta($post_id, 'king-addons-el-hf-display-on-canvas', '1');
897 + }
898 +
899 + // Redirect to Elementor editor
900 + wp_safe_redirect(admin_url('post.php?post=' . $post_id . '&action=elementor'));
901 + exit;
902 + }
903 +
904 + /**
905 + * Handle quick update submission.
906 + *
907 + * @return void
908 + */
909 + public function handleQuickUpdate(): void
910 + {
911 + if (!current_user_can('manage_options')) {
912 + wp_die(esc_html__('You do not have permission to perform this action.', 'king-addons'));
913 + }
914 +
915 + if (!isset($_POST['ka_hf_quick_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['ka_hf_quick_nonce'])), 'ka_hf_quick')) {
916 + wp_die(esc_html__('Invalid nonce.', 'king-addons'));
917 + }
918 +
919 + $template_id = isset($_POST['template_id']) ? (int) $_POST['template_id'] : 0;
920 + $type = isset($_POST['type']) ? sanitize_text_field(wp_unslash($_POST['type'])) : '';
921 +
922 + if ($template_id > 0 && !empty($type)) {
923 + update_post_meta($template_id, 'king_addons_el_hf_template_type', $type);
924 + }
925 +
926 + wp_safe_redirect(admin_url('admin.php?page=' . $this->menu_slug));
927 + exit;
928 + }
929 +
930 + /**
931 + * Handle inline toggle/delete actions.
932 + *
933 + * @return void
934 + */
935 + private function handleInlineActions(): void
936 + {
937 + $action = isset($_GET['action']) ? sanitize_text_field(wp_unslash($_GET['action'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
938 + $template_id = isset($_GET['template_id']) ? (int) $_GET['template_id'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
939 +
940 + if (!$template_id || empty($action)) {
941 + return;
942 + }
943 +
944 + if ('delete_template' === $action) {
945 + if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'] ?? '')), 'ka_hf_delete_' . $template_id)) {
946 + return;
947 + }
948 + wp_trash_post($template_id);
949 + }
950 + }
951 +
952 + /**
953 + * Prepare data for admin list table.
954 + *
955 + * @return array
956 + */
957 + private function prepareAdminTemplates(): array
958 + {
959 + $args = [
960 + 'post_type' => 'king-addons-el-hf',
961 + 'post_status' => ['publish', 'draft'],
962 + 'posts_per_page' => -1,
963 + 'orderby' => 'date',
964 + 'order' => 'DESC',
965 + ];
966 +
967 + $query = new WP_Query($args);
968 + $templates = [];
969 +
970 + if ($query->have_posts()) {
971 + while ($query->have_posts()) {
972 + $query->the_post();
973 + $post_id = get_the_ID();
974 + $templates[] = [
975 + 'id' => $post_id,
976 + 'title' => get_the_title(),
977 + 'type' => get_post_meta($post_id, 'king_addons_el_hf_template_type', true),
978 + 'include_locations' => get_post_meta($post_id, 'king_addons_el_hf_target_include_locations', true),
979 + 'exclude_locations' => get_post_meta($post_id, 'king_addons_el_hf_target_exclude_locations', true),
980 + 'user_roles' => get_post_meta($post_id, 'king_addons_el_hf_target_user_roles', true),
981 + ];
982 + }
983 + }
984 + wp_reset_postdata();
985 +
986 + return $templates;
987 + }
988 +
989 + /**
990 + * Summarize conditions to a short label for admin list.
991 + *
992 + * @param array $template Template data.
993 + *
994 + * @return string
995 + */
996 + private function summarizeConditions(array $template): string
997 + {
998 + $locations = $template['include_locations'] ?? [];
999 +
1000 + if (empty($locations) || empty($locations['rule'])) {
1001 + return esc_html__('All', 'king-addons');
1002 + }
1003 +
1004 + $rules = $locations['rule'];
1005 + $count = is_array($rules) ? count($rules) : 0;
1006 +
1007 + if ($count === 0) {
1008 + return esc_html__('All', 'king-addons');
1009 + }
1010 +
1011 + // Get the first rule label
1012 + $first_rule = $rules[0] ?? '';
1013 + $label = self::getLocation($first_rule);
1014 +
1015 + if ($count > 1) {
1016 + return sprintf(
1017 + esc_html__('%s + %d more', 'king-addons'),
1018 + $label,
1019 + $count - 1
1020 + );
1021 + }
1022 +
1023 + return $label ?: esc_html__('All', 'king-addons');
1024 + }
1025 +
1026 + /**
1027 + * SVG icon for template type.
1028 + *
1029 + * @param string $type_slug Template type slug.
1030 + *
1031 + * @return string
1032 + */
1033 + private function getTypeIconSvg(string $type_slug): string
1034 + {
1035 + switch ($type_slug) {
1036 + case 'header':
1037 + return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="18" height="6" rx="1"/><path d="M3 13h18M3 17h10"/></svg>';
1038 + case 'footer':
1039 + return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="15" width="18" height="6" rx="1"/><path d="M3 7h18M3 11h10"/></svg>';
1040 + default:
1041 + return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 3h18v6H3zM3 15h18v6H3z"/></svg>';
1042 + }
1043 + }
1044 +
1045 + /**
1046 + * Render modern CSS styles for admin page.
1047 + *
1048 + * @return void
1049 + */
1050 + private function renderModernStyles(): void
1051 + {
1052 + ?>
1053 + <style>
1054 + /* ================================================
1055 + Header & Footer Builder - Premium Admin Design
1056 + ================================================ */
1057 +
1058 + :root {
1059 + --ka-hf-font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", system-ui, sans-serif;
1060 + --ka-hf-bg: #f5f5f7;
1061 + --ka-hf-surface: #ffffff;
1062 + --ka-hf-text: #1d1d1f;
1063 + --ka-hf-text-secondary: #86868b;
1064 + --ka-hf-border: rgba(0, 0, 0, 0.06);
1065 + --ka-hf-accent: #0071e3;
1066 + --ka-hf-accent-hover: #0077ed;
1067 + --ka-hf-radius: 20px;
1068 + --ka-hf-radius-sm: 12px;
1069 + --ka-hf-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
1070 + --ka-hf-shadow-hover: 0 8px 32px rgba(0, 0, 0, 0.10);
1071 + --ka-hf-transition: all 0.3s cubic-bezier(0.25, 1, 0.5, 1);
1072 + }
1073 +
1074 + /* Dark theme support */
1075 + body.ka-v3-dark {
1076 + --ka-hf-bg: #1c1c1e;
1077 + --ka-hf-surface: #2c2c2e;
1078 + --ka-hf-text: #f5f5f7;
1079 + --ka-hf-text-secondary: #98989d;
1080 + --ka-hf-border: rgba(255, 255, 255, 0.1);
1081 + --ka-hf-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
1082 + --ka-hf-shadow-hover: 0 8px 32px rgba(0, 0, 0, 0.4);
1083 + }
1084 +
1085 + body.wp-admin #wpcontent,
1086 + body.wp-admin #wpbody,
1087 + body.wp-admin #wpbody-content {
1088 + background: var(--ka-hf-bg) !important;
1089 + padding: 0 !important;
1090 + }
1091 +
1092 + .ka-hf {
1093 + font-family: var(--ka-hf-font);
1094 + max-width: 1100px;
1095 + margin: 0 auto;
1096 + padding: 48px 40px 80px;
1097 + color: var(--ka-hf-text);
1098 + -webkit-font-smoothing: antialiased;
1099 + }
1100 + .ka-hf * { box-sizing: border-box; }
1101 +
1102 + /* Header */
1103 + .ka-hf-header {
1104 + display: flex;
1105 + justify-content: space-between;
1106 + align-items: flex-start;
1107 + margin-bottom: 40px;
1108 + gap: 20px;
1109 + }
1110 + .ka-hf-header-content {
1111 + display: flex;
1112 + align-items: flex-start;
1113 + gap: 16px;
1114 + }
1115 +
1116 + .ka-hf-header-titles {
1117 + display: flex;
1118 + flex-direction: column;
1119 + gap: 8px;
1120 + min-width: 0;
1121 + }
1122 +
1123 + .ka-hf-header-titles h1 {
1124 + font-size: 48px;
1125 + font-weight: 700;
1126 + letter-spacing: -0.025em;
1127 + margin: 0;
1128 + line-height: 1;
1129 + }
1130 + .ka-hf-header-titles p {
1131 + font-size: 21px;
1132 + color: var(--ka-hf-text-secondary);
1133 + margin: 0;
1134 + font-weight: 400;
1135 + }
1136 + .ka-hf-title-icon {
1137 + width: 76px;
1138 + height: 76px;
1139 + display: inline-flex;
1140 + align-items: center;
1141 + justify-content: center;
1142 + border-radius: 22px;
1143 + background: rgba(10, 132, 255, 0.18) !important;
1144 + color: #0a84ff !important;
1145 + flex: 0 0 auto;
1146 + }
1147 + .ka-hf-title-icon svg { width: 36px; height: 36px; }
1148 + .ka-hf-title-text {
1149 + background: linear-gradient(135deg, var(--ka-hf-text) 0%, var(--ka-hf-text-secondary) 100%);
1150 + -webkit-background-clip: text;
1151 + -webkit-text-fill-color: transparent;
1152 + background-clip: text;
1153 + }
1154 + .ka-hf-header-actions {
1155 + display: flex;
1156 + align-items: center;
1157 + gap: 12px;
1158 + flex-wrap: wrap;
1159 + justify-content: flex-end;
1160 + }
1161 +
1162 + /* Buttons */
1163 + .ka-hf-btn {
1164 + display: inline-flex;
1165 + align-items: center;
1166 + justify-content: center;
1167 + gap: 8px;
1168 + padding: 10px 18px;
1169 + font-size: 14px;
1170 + font-weight: 500;
1171 + text-decoration: none;
1172 + border-radius: 980px;
1173 + border: none;
1174 + cursor: pointer;
1175 + transition: var(--ka-hf-transition);
1176 + white-space: nowrap;
1177 + font-family: inherit;
1178 + }
1179 + .ka-hf-btn-icon {
1180 + font-size: 16px;
1181 + line-height: 1;
1182 + }
1183 + .ka-hf-btn-primary {
1184 + background: var(--ka-hf-accent);
1185 + color: #fff;
1186 + }
1187 + .ka-hf-btn-primary:hover {
1188 + background: var(--ka-hf-accent-hover);
1189 + color: #fff;
1190 + transform: scale(1.02);
1191 + }
1192 + .ka-hf-btn-secondary {
1193 + background: rgba(0, 0, 0, 0.04);
1194 + color: var(--ka-hf-text);
1195 + }
1196 + .ka-hf-btn-secondary:hover {
1197 + background: rgba(0, 0, 0, 0.08);
1198 + color: var(--ka-hf-text);
1199 + }
1200 +
1201 + /* Template Types - Compact Cards */
1202 + .ka-hf-types {
1203 + display: grid;
1204 + grid-template-columns: repeat(2, 1fr);
1205 + gap: 12px;
1206 + margin-bottom: 36px;
1207 + max-width: 480px;
1208 + }
1209 + .ka-hf-type {
1210 + position: relative;
1211 + display: flex;
1212 + flex-direction: column;
1213 + align-items: center;
1214 + padding: 20px 16px;
1215 + background: var(--ka-hf-surface);
1216 + border: 1px solid var(--ka-hf-border);
1217 + border-radius: var(--ka-hf-radius-sm);
1218 + color: var(--ka-hf-text);
1219 + transition: var(--ka-hf-transition);
1220 + cursor: pointer;
1221 + overflow: hidden;
1222 + }
1223 + .ka-hf-type:hover {
1224 + transform: translateY(-2px);
1225 + box-shadow: var(--ka-hf-shadow-hover);
1226 + border-color: var(--ka-hf-accent);
1227 + }
1228 + .ka-hf-type-icon {
1229 + width: 36px;
1230 + height: 36px;
1231 + margin-bottom: 10px;
1232 + color: var(--ka-hf-text-secondary);
1233 + transition: var(--ka-hf-transition);
1234 + }
1235 + .ka-hf-type:hover .ka-hf-type-icon {
1236 + transform: scale(1.1);
1237 + color: var(--ka-hf-accent);
1238 + }
1239 + .ka-hf-type-icon svg { width: 100%; height: 100%; }
1240 + .ka-hf-type-label {
1241 + font-size: 15px;
1242 + font-weight: 600;
1243 + margin-bottom: 2px;
1244 + text-align: center;
1245 + }
1246 + .ka-hf-type-desc {
1247 + font-size: 12px;
1248 + color: var(--ka-hf-text-secondary);
1249 + text-align: center;
1250 + }
1251 +
1252 + /* Section */
1253 + .ka-hf-section { margin-bottom: 48px; }
1254 + .ka-hf-section-header {
1255 + display: flex;
1256 + justify-content: space-between;
1257 + align-items: center;
1258 + margin-bottom: 18px;
1259 + gap: 12px;
1260 + }
1261 + .ka-hf-section-title {
1262 + font-size: 28px;
1263 + font-weight: 600;
1264 + letter-spacing: -0.01em;
1265 + margin: 0;
1266 + }
1267 + .ka-hf-section-actions {
1268 + display: flex;
1269 + align-items: center;
1270 + gap: 12px;
1271 + }
1272 + .ka-hf-section-count {
1273 + font-size: 15px;
1274 + color: var(--ka-hf-text-secondary);
1275 + background: var(--ka-hf-surface);
1276 + padding: 6px 14px;
1277 + border-radius: 20px;
1278 + border: 1px solid var(--ka-hf-border);
1279 + white-space: nowrap;
1280 + }
1281 +
1282 + /* Filters */
1283 + .ka-hf-filters {
1284 + display: inline-flex;
1285 + align-items: center;
1286 + gap: 6px;
1287 + padding: 6px;
1288 + border-radius: 980px;
1289 + border: 1px solid var(--ka-hf-border);
1290 + background: var(--ka-hf-surface);
1291 + }
1292 + .ka-hf-filter {
1293 + display: inline-flex;
1294 + align-items: center;
1295 + justify-content: center;
1296 + padding: 8px 12px;
1297 + border-radius: 980px;
1298 + text-decoration: none;
1299 + font-size: 13px;
1300 + font-weight: 600;
1301 + color: var(--ka-hf-text-secondary);
1302 + transition: var(--ka-hf-transition);
1303 + background: transparent;
1304 + border: none;
1305 + cursor: pointer;
1306 + font-family: inherit;
1307 + }
1308 + .ka-hf-filter.is-active {
1309 + background: rgba(0, 113, 227, 0.12);
1310 + color: var(--ka-hf-accent);
1311 + }
1312 + .ka-hf-filter:hover {
1313 + background: rgba(0, 0, 0, 0.04);
1314 + color: var(--ka-hf-text);
1315 + }
1316 +
1317 + /* Templates List */
1318 + .ka-hf-templates {
1319 + background: var(--ka-hf-surface);
1320 + border-radius: var(--ka-hf-radius);
1321 + border: 1px solid var(--ka-hf-border);
1322 + overflow: visible;
1323 + }
1324 + .ka-hf-template {
1325 + display: grid;
1326 + grid-template-columns: auto 1fr auto auto;
1327 + align-items: center;
1328 + gap: 20px;
1329 + padding: 20px 24px;
1330 + border-bottom: 1px solid var(--ka-hf-border);
1331 + transition: var(--ka-hf-transition);
1332 + }
1333 + .ka-hf-template:last-child { border-bottom: none; }
1334 + .ka-hf-template:hover { background: rgba(0, 113, 227, 0.03); }
1335 +
1336 + .ka-hf-template-info {
1337 + display: flex;
1338 + flex-direction: column;
1339 + gap: 4px;
1340 + min-width: 0;
1341 + }
1342 + .ka-hf-template-title {
1343 + font-size: 16px;
1344 + font-weight: 500;
1345 + color: var(--ka-hf-text);
1346 + text-decoration: none;
1347 + display: inline-flex;
1348 + align-items: center;
1349 + gap: 8px;
1350 + min-width: 0;
1351 + transition: var(--ka-hf-transition);
1352 + }
1353 + .ka-hf-template-title-icon {
1354 + width: 18px;
1355 + height: 18px;
1356 + display: inline-flex;
1357 + align-items: center;
1358 + justify-content: center;
1359 + color: var(--ka-hf-text-secondary);
1360 + flex: 0 0 auto;
1361 + }
1362 + .ka-hf-template-title-icon svg { width: 18px; height: 18px; }
1363 + .ka-hf-template-title-text {
1364 + min-width: 0;
1365 + white-space: nowrap;
1366 + overflow: hidden;
1367 + text-overflow: ellipsis;
1368 + }
1369 + .ka-hf-template-title:hover { color: var(--ka-hf-accent); }
1370 + .ka-hf-template-meta {
1371 + display: flex;
1372 + align-items: center;
1373 + gap: 12px;
1374 + font-size: 13px;
1375 + color: var(--ka-hf-text-secondary);
1376 + flex-wrap: wrap;
1377 + }
1378 + .ka-hf-template-type {
1379 + display: inline-flex;
1380 + align-items: center;
1381 + gap: 6px;
1382 + }
1383 + .ka-hf-template-type::before {
1384 + content: '';
1385 + width: 6px;
1386 + height: 6px;
1387 + background: var(--ka-hf-accent);
1388 + border-radius: 50%;
1389 + }
1390 +
1391 + .ka-hf-template-status {
1392 + display: inline-flex;
1393 + align-items: center;
1394 + padding: 6px 14px;
1395 + font-size: 13px;
1396 + font-weight: 600;
1397 + border-radius: 8px;
1398 + white-space: nowrap;
1399 + min-width: 90px;
1400 + justify-content: center;
1401 + justify-self: start;
1402 + }
1403 + .ka-hf-template-status.is-enabled {
1404 + background: rgba(52, 199, 89, 0.15);
1405 + color: #30d158;
1406 + }
1407 + .ka-hf-template-status.is-disabled {
1408 + background: rgba(255, 149, 0, 0.15);
1409 + color: #ff9f0a;
1410 + }
1411 +
1412 + .ka-hf-template-condition {
1413 + display: inline-flex;
1414 + align-items: center;
1415 + gap: 8px;
1416 + padding: 10px 18px;
1417 + min-height: 40px;
1418 + font-size: 14px;
1419 + font-weight: 500;
1420 + border-radius: 980px;
1421 + background: rgba(0, 113, 227, 0.10);
1422 + color: var(--ka-hf-accent);
1423 + max-width: 240px;
1424 + overflow: hidden;
1425 + text-overflow: ellipsis;
1426 + white-space: nowrap;
1427 + border: none;
1428 + cursor: default;
1429 + }
1430 + .ka-hf-template-condition svg {
1431 + width: 18px;
1432 + height: 18px;
1433 + flex-shrink: 0;
1434 + opacity: 0.7;
1435 + }
1436 +
1437 + .ka-hf-template-actions {
1438 + display: flex;
1439 + align-items: center;
1440 + gap: 12px;
1441 + flex-wrap: nowrap;
1442 + }
1443 +
1444 + /* Dropdown */
1445 + .ka-hf-dropdown { position: relative; }
1446 + .ka-hf-dropdown-trigger {
1447 + display: flex;
1448 + align-items: center;
1449 + justify-content: center;
1450 + width: 40px;
1451 + height: 40px;
1452 + border-radius: 10px;
1453 + background: transparent;
1454 + border: 1px solid transparent;
1455 + cursor: pointer;
1456 + transition: var(--ka-hf-transition);
1457 + color: var(--ka-hf-text-secondary);
1458 + }
1459 + .ka-hf-dropdown-trigger:hover {
1460 + background: var(--ka-hf-surface);
1461 + border-color: var(--ka-hf-border);
1462 + color: var(--ka-hf-text);
1463 + }
1464 + .ka-hf-dropdown-trigger svg { width: 20px; height: 20px; }
1465 + .ka-hf-dropdown-menu {
1466 + position: absolute;
1467 + top: 100%;
1468 + right: 0;
1469 + z-index: 100;
1470 + min-width: 180px;
1471 + padding: 8px 0;
1472 + background: var(--ka-hf-surface);
1473 + border: 1px solid var(--ka-hf-border);
1474 + border-radius: var(--ka-hf-radius-sm);
1475 + box-shadow: var(--ka-hf-shadow-hover);
1476 + opacity: 0;
1477 + visibility: hidden;
1478 + transform: translateY(-8px);
1479 + transition: var(--ka-hf-transition);
1480 + }
1481 + .ka-hf-dropdown.is-open .ka-hf-dropdown-menu {
1482 + opacity: 1;
1483 + visibility: visible;
1484 + transform: translateY(4px);
1485 + }
1486 + .ka-hf-dropdown-item {
1487 + display: flex;
1488 + align-items: center;
1489 + gap: 10px;
1490 + padding: 10px 16px;
1491 + font-size: 14px;
1492 + color: var(--ka-hf-text);
1493 + text-decoration: none;
1494 + cursor: pointer;
1495 + transition: var(--ka-hf-transition);
1496 + background: transparent;
1497 + border: none;
1498 + width: 100%;
1499 + text-align: left;
1500 + font-family: inherit;
1501 + }
1502 + .ka-hf-dropdown-item:hover { background: var(--ka-hf-border); }
1503 + .ka-hf-dropdown-item.is-danger { color: #ff3b30; }
1504 +
1505 + /* Empty state */
1506 + .ka-hf-empty {
1507 + padding: 60px 24px;
1508 + text-align: center;
1509 + }
1510 + .ka-hf-filter-empty {
1511 + margin-top: 12px;
1512 + padding: 48px 24px;
1513 + text-align: center;
1514 + background: var(--ka-hf-surface);
1515 + border-radius: var(--ka-hf-radius);
1516 + border: 1px solid var(--ka-hf-border);
1517 + }
1518 + .ka-hf-empty-title {
1519 + margin: 0 0 8px;
1520 + font-size: 20px;
1521 + font-weight: 600;
1522 + }
1523 + .ka-hf-empty-desc {
1524 + margin: 0 0 18px;
1525 + color: var(--ka-hf-text-secondary);
1526 + font-size: 15px;
1527 + }
1528 +
1529 + /* Modal */
1530 + .ka-hf-modal-overlay {
1531 + position: fixed;
1532 + top: 0;
1533 + left: 0;
1534 + right: 0;
1535 + bottom: 0;
1536 + z-index: 100000;
1537 + background: rgba(0, 0, 0, 0.55);
1538 + backdrop-filter: blur(12px);
1539 + -webkit-backdrop-filter: blur(12px);
1540 + display: flex;
1541 + align-items: center;
1542 + justify-content: center;
1543 + opacity: 0;
1544 + visibility: hidden;
1545 + transition: opacity 0.25s ease, visibility 0.25s ease;
1546 + padding: 20px;
1547 + }
1548 + .ka-hf-modal-overlay.is-open {
1549 + opacity: 1;
1550 + visibility: visible;
1551 + }
1552 + .ka-hf-modal {
1553 + width: 100%;
1554 + max-width: 500px;
1555 + max-height: 90vh;
1556 + overflow-y: auto;
1557 + padding: 32px 36px 28px;
1558 + background: var(--ka-hf-surface);
1559 + border-radius: 20px;
1560 + box-shadow: 0 32px 100px rgba(0, 0, 0, 0.35);
1561 + transform: scale(0.92) translateY(20px);
1562 + transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.25s ease;
1563 + opacity: 0;
1564 + }
1565 + .ka-hf-modal-overlay.is-open .ka-hf-modal {
1566 + transform: scale(1) translateY(0);
1567 + opacity: 1;
1568 + }
1569 + .ka-hf-modal h3 {
1570 + font-size: 24px;
1571 + font-weight: 700;
1572 + margin: 0 0 4px;
1573 + color: var(--ka-hf-text);
1574 + letter-spacing: -0.02em;
1575 + line-height: 1.2;
1576 + }
1577 + .ka-hf-modal-desc {
1578 + font-size: 14px;
1579 + color: var(--ka-hf-text-secondary);
1580 + margin: 0 0 28px;
1581 + line-height: 1.5;
1582 + }
1583 + .ka-hf-form-group {
1584 + margin-bottom: 20px;
1585 + }
1586 + .ka-hf-form-label {
1587 + display: block;
1588 + font-size: 12px;
1589 + font-weight: 600;
1590 + color: var(--ka-hf-text-secondary);
1591 + margin-bottom: 8px;
1592 + text-transform: uppercase;
1593 + letter-spacing: 0.6px;
1594 + }
1595 + .ka-hf-form-desc {
1596 + font-size: 13px;
1597 + color: var(--ka-hf-text-secondary);
1598 + margin: 4px 0 8px;
1599 + }
1600 + .ka-hf-modal-input {
1601 + width: 100% !important;
1602 + padding: 16px 20px !important;
1603 + font-size: 17px !important;
1604 + font-family: inherit !important;
1605 + font-weight: 400 !important;
1606 + border: 2px solid rgba(0, 0, 0, 0.12) !important;
1607 + border-radius: 14px !important;
1608 + background: #f5f5f7 !important;
1609 + color: #1d1d1f !important;
1610 + transition: all 0.2s ease !important;
1611 + box-shadow: none !important;
1612 + -webkit-appearance: none !important;
1613 + appearance: none !important;
1614 + line-height: 1.4 !important;
1615 + height: auto !important;
1616 + margin: 0 !important;
1617 + }
1618 + .ka-hf-modal-input:focus {
1619 + outline: none !important;
1620 + border-color: #0071e3 !important;
1621 + background: #ffffff !important;
1622 + box-shadow: 0 0 0 4px rgba(0, 113, 227, 0.15) !important;
1623 + }
1624 + .ka-hf-form-select {
1625 + width: 100% !important;
1626 + padding: 16px 52px 16px 20px !important;
1627 + font-size: 17px !important;
1628 + font-family: inherit !important;
1629 + font-weight: 400 !important;
1630 + border: 2px solid rgba(0, 0, 0, 0.12) !important;
1631 + border-radius: 14px !important;
1632 + background-color: #f5f5f7 !important;
1633 + color: #1d1d1f !important;
1634 + transition: all 0.2s ease !important;
1635 + cursor: pointer !important;
1636 + appearance: none !important;
1637 + -webkit-appearance: none !important;
1638 + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%231d1d1f' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") !important;
1639 + background-repeat: no-repeat !important;
1640 + background-position: right 18px center !important;
1641 + background-size: 20px !important;
1642 + line-height: 1.4 !important;
1643 + height: auto !important;
1644 + margin: 0 !important;
1645 + box-shadow: none !important;
1646 + }
1647 + .ka-hf-form-select:focus {
1648 + outline: none !important;
1649 + border-color: #0071e3 !important;
1650 + background-color: #ffffff !important;
1651 + box-shadow: 0 0 0 4px rgba(0, 113, 227, 0.15) !important;
1652 + }
1653 + /* Multi-select styles */
1654 + .ka-hf-form-select.ka-hf-multi-select {
1655 + background-image: none !important;
1656 + padding-right: 20px !important;
1657 + min-height: 120px !important;
1658 + }
1659 + .ka-hf-form-select.ka-hf-multi-select option {
1660 + padding: 8px 12px !important;
1661 + border-radius: 6px !important;
1662 + margin: 2px 4px !important;
1663 + }
1664 + .ka-hf-form-select.ka-hf-multi-select option:checked {
1665 + background: linear-gradient(0deg, rgba(0, 113, 227, 0.15) 0%, rgba(0, 113, 227, 0.15) 100%) !important;
1666 + color: #0071e3 !important;
1667 + }
1668 + .ka-hf-form-select.ka-hf-multi-select optgroup {
1669 + font-weight: 600 !important;
1670 + font-style: normal !important;
1671 + padding: 8px 4px 4px !important;
1672 + color: var(--ka-hf-text-secondary) !important;
1673 + }
1674 + .ka-hf-modal-actions {
1675 + display: flex;
1676 + gap: 10px;
1677 + margin-top: 24px;
1678 + justify-content: flex-end;
1679 + flex-wrap: wrap;
1680 + }
1681 + .ka-hf-modal-actions .ka-hf-btn {
1682 + padding: 12px 20px;
1683 + font-size: 14px;
1684 + font-weight: 500;
1685 + }
1686 + .ka-hf-modal-actions .ka-hf-btn-primary {
1687 + min-width: 180px;
1688 + }
1689 +
1690 + .ka-hf-conditions-wrap {
1691 + margin-bottom: 8px;
1692 + }
1693 +
1694 + /* Create modal rule row */
1695 + .ka-hf-create-rule-row {
1696 + display: flex;
1697 + flex-direction: column;
1698 + gap: 10px;
1699 + }
1700 + .ka-hf-create-rule-row .ka-hf-form-select {
1701 + flex: 1;
1702 + }
1703 + .ka-hf-create-rule-row .ka-hf-specific-input {
1704 + margin-top: 0;
1705 + }
1706 +
1707 + /* Form spacing improvements */
1708 + .ka-hf-form-group {
1709 + margin-bottom: 18px;
1710 + }
1711 + .ka-hf-form-group:last-of-type {
1712 + margin-bottom: 8px;
1713 + }
1714 + .ka-hf-modal-desc {
1715 + margin-bottom: 24px !important;
1716 + }
1717 + .ka-hf-form-desc {
1718 + margin: 2px 0 6px;
1719 + font-size: 12px;
1720 + opacity: 0.8;
1721 + }
1722 +
1723 + /* Smaller inputs */
1724 + .ka-hf-modal-input,
1725 + .ka-hf-form-select {
1726 + padding: 12px 16px !important;
1727 + font-size: 15px !important;
1728 + border-radius: 12px !important;
1729 + }
1730 + .ka-hf-form-select {
1731 + padding-right: 44px !important;
1732 + background-position: right 14px center !important;
1733 + }
1734 +
1735 + /* Specific input styling */
1736 + .ka-hf-specific-input {
1737 + flex: 1;
1738 + }
1739 + .ka-hf-specific-input[style*="display: block"] {
1740 + margin-top: 8px;
1741 + }
1742 +
1743 + /* Clickable condition button */
1744 + .ka-hf-template-condition.ka-hf-open-conditions {
1745 + cursor: pointer;
1746 + transition: var(--ka-hf-transition);
1747 + }
1748 + .ka-hf-template-condition.ka-hf-open-conditions:hover {
1749 + background: rgba(0, 113, 227, 0.18);
1750 + transform: scale(1.02);
1751 + }
1752 +
1753 + /* Conditions Modal - Larger width */
1754 + .ka-hf-modal.ka-hf-modal-conditions {
1755 + max-width: 600px;
1756 + position: relative;
1757 + }
1758 +
1759 + /* Rules container */
1760 + .ka-hf-rules-container {
1761 + display: flex;
1762 + flex-direction: column;
1763 + gap: 8px;
1764 + margin-bottom: 10px;
1765 + }
1766 +
1767 + .ka-hf-rule-row {
1768 + display: flex;
1769 + gap: 8px;
1770 + align-items: center;
1771 + }
1772 +
1773 + .ka-hf-rule-row .ka-hf-rule-select {
1774 + flex: 1;
1775 + min-width: 180px;
1776 + }
1777 +
1778 + .ka-hf-rule-row .ka-hf-specific-input {
1779 + flex: 0 0 180px;
1780 + max-width: 180px;
1781 + }
1782 +
1783 + .ka-hf-remove-rule-btn {
1784 + width: 36px;
1785 + height: 36px;
1786 + display: flex;
1787 + align-items: center;
1788 + justify-content: center;
1789 + background: rgba(255, 59, 48, 0.1);
1790 + border: none;
1791 + border-radius: 10px;
1792 + color: #ff3b30;
1793 + cursor: pointer;
1794 + transition: var(--ka-hf-transition);
1795 + flex-shrink: 0;
1796 + }
1797 + .ka-hf-remove-rule-btn:hover {
1798 + background: rgba(255, 59, 48, 0.2);
1799 + }
1800 +
1801 + .ka-hf-add-rule-btn {
1802 + display: inline-flex;
1803 + align-items: center;
1804 + gap: 5px;
1805 + padding: 8px 14px;
1806 + font-size: 12px;
1807 + font-weight: 500;
1808 + color: var(--ka-hf-accent);
1809 + background: rgba(0, 113, 227, 0.06);
1810 + border: 1px dashed rgba(0, 113, 227, 0.25);
1811 + border-radius: 8px;
1812 + cursor: pointer;
1813 + transition: var(--ka-hf-transition);
1814 + font-family: inherit;
1815 + }
1816 + .ka-hf-add-rule-btn:hover {
1817 + background: rgba(0, 113, 227, 0.12);
1818 + border-color: var(--ka-hf-accent);
1819 + }
1820 + .ka-hf-add-rule-btn svg {
1821 + width: 14px;
1822 + height: 14px;
1823 + }
1824 +
1825 + /* Saving overlay */
1826 + .ka-hf-saving-overlay {
1827 + position: absolute;
1828 + top: 0;
1829 + left: 0;
1830 + right: 0;
1831 + bottom: 0;
1832 + background: rgba(255, 255, 255, 0.9);
1833 + display: flex;
1834 + flex-direction: column;
1835 + align-items: center;
1836 + justify-content: center;
1837 + gap: 12px;
1838 + border-radius: 24px;
1839 + font-size: 15px;
1840 + font-weight: 500;
1841 + color: var(--ka-hf-text);
1842 + z-index: 10;
1843 + }
1844 + body.ka-v3-dark .ka-hf-saving-overlay {
1845 + background: rgba(44, 44, 46, 0.95);
1846 + }
1847 +
1848 + .ka-hf-spinner {
1849 + width: 32px;
1850 + height: 32px;
1851 + border: 3px solid var(--ka-hf-border);
1852 + border-top-color: var(--ka-hf-accent);
1853 + border-radius: 50%;
1854 + animation: ka-hf-spin 0.8s linear infinite;
1855 + }
1856 +
1857 + @keyframes ka-hf-spin {
1858 + to { transform: rotate(360deg); }
1859 + }
1860 +
1861 + /* Dark theme overrides for secondary button */
1862 + body.ka-v3-dark .ka-hf-btn-secondary {
1863 + background: rgba(255, 255, 255, 0.08);
1864 + color: var(--ka-hf-text);
1865 + }
1866 + body.ka-v3-dark .ka-hf-btn-secondary:hover {
1867 + background: rgba(255, 255, 255, 0.14);
1868 + }
1869 +
1870 + /* Dark theme modal inputs */
1871 + body.ka-v3-dark .ka-hf-modal-input,
1872 + body.ka-v3-dark .ka-hf-form-select {
1873 + background-color: #3a3a3c !important;
1874 + border-color: rgba(255, 255, 255, 0.15) !important;
1875 + color: #f5f5f7 !important;
1876 + }
1877 + body.ka-v3-dark .ka-hf-modal-input:focus,
1878 + body.ka-v3-dark .ka-hf-form-select:focus {
1879 + background-color: #48484a !important;
1880 + border-color: #0071e3 !important;
1881 + }
1882 + body.ka-v3-dark .ka-hf-form-select {
1883 + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f7' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") !important;
1884 + }
1885 +
1886 + /* Dark theme modal */
1887 + body.ka-v3-dark .ka-hf-modal {
1888 + background: var(--ka-hf-surface);
1889 + }
1890 +
1891 + /* Responsive */
1892 + @media (max-width: 782px) {
1893 + .ka-hf { padding: 36px 20px 70px; }
1894 + .ka-hf-header { flex-direction: column; align-items: flex-start; }
1895 + .ka-hf-header-titles h1 { font-size: 36px; }
1896 + .ka-hf-title-icon { width: 64px; height: 64px; border-radius: 18px; }
1897 + .ka-hf-title-icon svg { width: 30px; height: 30px; }
1898 + .ka-hf-template { grid-template-columns: 1fr; gap: 12px; }
1899 + .ka-hf-template-actions { justify-content: flex-start; flex-wrap: wrap; }
1900 + .ka-hf-nav-tabs { flex-wrap: wrap; }
1901 + .ka-hf-section-header { flex-direction: column; align-items: stretch; }
1902 + .ka-hf-section-actions { flex-wrap: wrap; width: 100%; }
1903 + .ka-hf-filters { flex-wrap: wrap; border-radius: 16px; max-width: 100%; }
1904 + }
1905 +
1906 + /* Navigation Tabs */
1907 + .ka-hf-nav-tabs {
1908 + display: inline-flex;
1909 + align-items: center;
1910 + gap: 4px;
1911 + padding: 4px;
1912 + background: var(--ka-hf-surface);
1913 + border: 1px solid var(--ka-hf-border);
1914 + border-radius: 14px;
1915 + margin-bottom: 32px;
1916 + }
1917 + .ka-hf-nav-tab {
1918 + display: inline-flex;
1919 + align-items: center;
1920 + gap: 8px;
1921 + padding: 12px 20px;
1922 + font-size: 14px;
1923 + font-weight: 500;
1924 + color: var(--ka-hf-text-secondary);
1925 + text-decoration: none;
1926 + border-radius: 10px;
1927 + transition: var(--ka-hf-transition);
1928 + }
1929 + .ka-hf-nav-tab svg {
1930 + opacity: 0.7;
1931 + transition: var(--ka-hf-transition);
1932 + }
1933 + .ka-hf-nav-tab:hover {
1934 + color: var(--ka-hf-text);
1935 + background: rgba(0, 0, 0, 0.03);
1936 + }
1937 + .ka-hf-nav-tab:hover svg {
1938 + opacity: 1;
1939 + }
1940 + .ka-hf-nav-tab.is-active {
1941 + background: var(--ka-hf-accent);
1942 + color: #fff;
1943 + }
1944 + .ka-hf-nav-tab.is-active svg {
1945 + opacity: 1;
1946 + }
1947 + body.ka-v3-dark .ka-hf-nav-tab:hover {
1948 + background: rgba(255, 255, 255, 0.05);
1949 + }
1950 +
1951 + /* Settings Tab Styles */
1952 + .ka-hf-settings-section {
1953 + max-width: 700px;
1954 + }
1955 + .ka-hf-settings-form {
1956 + margin: 0;
1957 + }
1958 + .ka-hf-settings-card {
1959 + background: var(--ka-hf-surface);
1960 + border: 1px solid var(--ka-hf-border);
1961 + border-radius: var(--ka-hf-radius);
1962 + padding: 32px;
1963 + }
1964 + .ka-hf-settings-card-title {
1965 + font-size: 20px;
1966 + font-weight: 600;
1967 + margin: 0 0 8px 0;
1968 + color: var(--ka-hf-text);
1969 + }
1970 + .ka-hf-settings-card-desc {
1971 + font-size: 14px;
1972 + color: var(--ka-hf-text-secondary);
1973 + margin: 0 0 24px 0;
1974 + line-height: 1.5;
1975 + }
1976 + .ka-hf-settings-options {
1977 + display: flex;
1978 + flex-direction: column;
1979 + gap: 16px;
1980 + margin-bottom: 28px;
1981 + }
1982 + .ka-hf-settings-option {
1983 + display: flex;
1984 + align-items: flex-start;
1985 + gap: 14px;
1986 + padding: 20px;
1987 + background: rgba(0, 0, 0, 0.02);
1988 + border: 1px solid var(--ka-hf-border);
1989 + border-radius: var(--ka-hf-radius-sm);
1990 + cursor: pointer;
1991 + transition: var(--ka-hf-transition);
1992 + }
1993 + .ka-hf-settings-option:hover {
1994 + border-color: var(--ka-hf-accent);
1995 + background: rgba(0, 113, 227, 0.02);
1996 + }
1997 + .ka-hf-settings-option:has(input:checked) {
1998 + border-color: var(--ka-hf-accent);
1999 + background: rgba(0, 113, 227, 0.05);
2000 + }
2001 + .ka-hf-settings-option input[type="radio"] {
2002 + margin: 3px 0 0 0;
2003 + flex-shrink: 0;
2004 + accent-color: var(--ka-hf-accent);
2005 + width: 18px;
2006 + height: 18px;
2007 + }
2008 + .ka-hf-settings-option-content {
2009 + display: flex;
2010 + flex-direction: column;
2011 + gap: 4px;
2012 + }
2013 + .ka-hf-settings-option-title {
2014 + font-size: 15px;
2015 + font-weight: 600;
2016 + color: var(--ka-hf-text);
2017 + }
2018 + .ka-hf-settings-option-desc {
2019 + font-size: 13px;
2020 + color: var(--ka-hf-text-secondary);
2021 + line-height: 1.5;
2022 + }
2023 + .ka-hf-settings-actions {
2024 + padding-top: 4px;
2025 + }
2026 + body.ka-v3-dark .ka-hf-settings-option {
2027 + background: rgba(255, 255, 255, 0.02);
2028 + }
2029 + body.ka-v3-dark .ka-hf-settings-option:hover {
2030 + background: rgba(0, 113, 227, 0.08);
2031 + }
2032 + body.ka-v3-dark .ka-hf-settings-option:has(input:checked) {
2033 + background: rgba(0, 113, 227, 0.12);
2034 + }
2035 + </style>
2036 +
2037 + <script>
2038 + document.addEventListener('DOMContentLoaded', function() {
2039 + var addNewButton = document.getElementById('ka-hf-add-new');
2040 + var addNewEmptyButton = document.getElementById('ka-hf-add-new-empty');
2041 + var addNewFilterEmptyButton = document.getElementById('ka-hf-add-new-filter-empty');
2042 + var modal = document.getElementById('ka-hf-modal');
2043 + var closeButtons = document.querySelectorAll('.ka-hf-modal-close');
2044 + var typeSelect = document.getElementById('ka-hf-type');
2045 + var createUserRolesContainer = document.getElementById('ka-hf-create-user-roles');
2046 + var createAddUserRoleBtn = document.getElementById('ka-hf-create-add-user-role');
2047 +
2048 + var renameModal = document.getElementById('ka-hf-rename-modal');
2049 + var renameCloseButtons = document.querySelectorAll('.ka-hf-rename-close');
2050 + var renameSaveBtn = document.getElementById('ka-hf-rename-save');
2051 + var renameIdInput = document.getElementById('ka-hf-rename-id');
2052 + var renameTitleInput = document.getElementById('ka-hf-rename-title-input');
2053 +
2054 + var openModal = function() {
2055 + if (modal) {
2056 + modal.classList.add('is-open');
2057 + modal.setAttribute('aria-hidden', 'false');
2058 + }
2059 +
2060 + // Ensure at least one user role row exists in create modal
2061 + if (createUserRolesContainer && typeof addUserRoleRow === 'function') {
2062 + if (createUserRolesContainer.children.length === 0) {
2063 + addUserRoleRow(createUserRolesContainer, 'all', true);
2064 + }
2065 + }
2066 + };
2067 +
2068 + var closeModal = function() {
2069 + if (modal) {
2070 + modal.classList.remove('is-open');
2071 + modal.setAttribute('aria-hidden', 'true');
2072 + }
2073 + };
2074 +
2075 + if (addNewButton) {
2076 + addNewButton.addEventListener('click', function(e) {
2077 + e.preventDefault();
2078 + openModal();
2079 + });
2080 + }
2081 +
2082 + if (addNewEmptyButton) {
2083 + addNewEmptyButton.addEventListener('click', function(e) {
2084 + e.preventDefault();
2085 + openModal();
2086 + });
2087 + }
2088 +
2089 + if (addNewFilterEmptyButton) {
2090 + addNewFilterEmptyButton.addEventListener('click', function(e) {
2091 + e.preventDefault();
2092 + openModal();
2093 + });
2094 + }
2095 +
2096 + // Type cards: preselect type and open create modal
2097 + var typeButtons = document.querySelectorAll('.ka-hf-type');
2098 + typeButtons.forEach(function(btn) {
2099 + btn.addEventListener('click', function(e) {
2100 + e.preventDefault();
2101 + var type = btn.getAttribute('data-ka-hf-type');
2102 + if (typeSelect && type) {
2103 + typeSelect.value = type;
2104 + }
2105 + openModal();
2106 + });
2107 + });
2108 +
2109 + closeButtons.forEach(function(button) {
2110 + button.addEventListener('click', closeModal);
2111 + });
2112 +
2113 + // Backdrop click closes
2114 + if (modal) {
2115 + modal.addEventListener('click', function(e) {
2116 + if (e.target === modal) {
2117 + closeModal();
2118 + }
2119 + });
2120 + }
2121 +
2122 + // ESC closes
2123 + document.addEventListener('keydown', function(e) {
2124 + if (e.key === 'Escape') {
2125 + closeModal();
2126 + }
2127 + });
2128 +
2129 + // Dropdown toggles
2130 + var dropdowns = document.querySelectorAll('[data-ka-dropdown]');
2131 + dropdowns.forEach(function(dropdown) {
2132 + var trigger = dropdown.querySelector('.ka-hf-dropdown-trigger');
2133 + if (trigger) {
2134 + trigger.addEventListener('click', function(e) {
2135 + e.stopPropagation();
2136 + dropdown.classList.toggle('is-open');
2137 + });
2138 + }
2139 + });
2140 +
2141 + document.addEventListener('click', function() {
2142 + dropdowns.forEach(function(dropdown) {
2143 + dropdown.classList.remove('is-open');
2144 + });
2145 + });
2146 +
2147 + // ==========================================
2148 + // JS Filtering (All/Headers/Footers)
2149 + // ==========================================
2150 + var filterButtons = document.querySelectorAll('.ka-hf-filter[data-filter]');
2151 + var templateItems = document.querySelectorAll('.ka-hf-template[data-template-type]');
2152 + var templateCount = document.querySelector('.ka-hf-section-count');
2153 + var filterEmptyState = document.querySelector('.ka-hf-filter-empty');
2154 + var templatesList = document.querySelector('.ka-hf-templates');
2155 +
2156 + var updateCount = function(count) {
2157 + if (templateCount) {
2158 + templateCount.textContent = count + ' ' + (count === 1 ? '<?php echo esc_js(__('item', 'king-addons')); ?>' : '<?php echo esc_js(__('items', 'king-addons')); ?>');
2159 + }
2160 + };
2161 +
2162 + filterButtons.forEach(function(btn) {
2163 + btn.addEventListener('click', function(e) {
2164 + e.preventDefault();
2165 + var filter = btn.getAttribute('data-filter');
2166 +
2167 + // Update active state
2168 + filterButtons.forEach(function(b) { b.classList.remove('is-active'); });
2169 + btn.classList.add('is-active');
2170 +
2171 + // Filter templates
2172 + var visibleCount = 0;
2173 + templateItems.forEach(function(item) {
2174 + var type = item.getAttribute('data-template-type');
2175 + if (filter === 'all' || type === filter) {
2176 + item.style.display = '';
2177 + visibleCount++;
2178 + } else {
2179 + item.style.display = 'none';
2180 + }
2181 + });
2182 +
2183 + updateCount(visibleCount);
2184 +
2185 + if (filterEmptyState && templatesList) {
2186 + if (visibleCount === 0) {
2187 + filterEmptyState.style.display = 'block';
2188 + templatesList.style.display = 'none';
2189 + } else {
2190 + filterEmptyState.style.display = 'none';
2191 + templatesList.style.display = '';
2192 + }
2193 + }
2194 + });
2195 + });
2196 +
2197 + // ==========================================
2198 + // Rename Template
2199 + // ==========================================
2200 + var renameBtns = document.querySelectorAll('.ka-hf-rename-btn');
2201 + renameBtns.forEach(function(btn) {
2202 + btn.addEventListener('click', function(e) {
2203 + e.preventDefault();
2204 + e.stopPropagation();
2205 + var templateId = btn.getAttribute('data-id');
2206 + var currentTitle = btn.getAttribute('data-title');
2207 + if (renameModal && renameIdInput && renameTitleInput) {
2208 + renameIdInput.value = templateId || '';
2209 + renameTitleInput.value = currentTitle || '';
2210 + renameModal.classList.add('is-open');
2211 + renameModal.setAttribute('aria-hidden', 'false');
2212 + renameTitleInput.focus();
2213 + renameTitleInput.select();
2214 + }
2215 + });
2216 + });
2217 +
2218 + if (renameCloseButtons.length) {
2219 + renameCloseButtons.forEach(function(btn) {
2220 + btn.addEventListener('click', function() {
2221 + if (renameModal) {
2222 + renameModal.classList.remove('is-open');
2223 + renameModal.setAttribute('aria-hidden', 'true');
2224 + }
2225 + });
2226 + });
2227 + }
2228 +
2229 + if (renameModal) {
2230 + renameModal.addEventListener('click', function(e) {
2231 + if (e.target === renameModal) {
2232 + renameModal.classList.remove('is-open');
2233 + renameModal.setAttribute('aria-hidden', 'true');
2234 + }
2235 + });
2236 + }
2237 +
2238 + if (renameSaveBtn) {
2239 + renameSaveBtn.addEventListener('click', function() {
2240 + if (!renameIdInput || !renameTitleInput) return;
2241 + var templateId = renameIdInput.value;
2242 + var newTitle = (renameTitleInput.value || '').trim();
2243 + if (!templateId || !newTitle) return;
2244 +
2245 + var formData = new FormData();
2246 + formData.append('action', 'ka_hf_rename_template');
2247 + formData.append('nonce', kaHfNonce);
2248 + formData.append('template_id', templateId);
2249 + formData.append('new_title', newTitle);
2250 +
2251 + fetch(kaHfAjaxUrl, {
2252 + method: 'POST',
2253 + body: formData
2254 + })
2255 + .then(function(response) { return response.json(); })
2256 + .then(function(data) {
2257 + if (data.success) {
2258 + var templateEl = document.querySelector('.ka-hf-template[data-template-id="' + templateId + '"]');
2259 + if (templateEl) {
2260 + var titleText = templateEl.querySelector('.ka-hf-template-title-text');
2261 + if (titleText) titleText.textContent = newTitle;
2262 + var renameBtn = templateEl.querySelector('.ka-hf-rename-btn');
2263 + if (renameBtn) renameBtn.setAttribute('data-title', newTitle);
2264 + }
2265 + if (renameModal) {
2266 + renameModal.classList.remove('is-open');
2267 + renameModal.setAttribute('aria-hidden', 'true');
2268 + }
2269 + } else {
2270 + alert(data.data && data.data.message ? data.data.message : '<?php echo esc_js(__('Error renaming template', 'king-addons')); ?>');
2271 + }
2272 + })
2273 + .catch(function(err) {
2274 + alert('<?php echo esc_js(__('Error renaming template', 'king-addons')); ?>');
2275 + // console.error(err);
2276 + });
2277 + });
2278 + }
2279 +
2280 + // ==========================================
2281 + // Enable/Disable Template
2282 + // ==========================================
2283 + var toggleStatusBtns = document.querySelectorAll('.ka-hf-toggle-status-btn');
2284 + toggleStatusBtns.forEach(function(btn) {
2285 + btn.addEventListener('click', function(e) {
2286 + e.preventDefault();
2287 + e.stopPropagation();
2288 + var templateId = btn.getAttribute('data-id');
2289 + var currentStatus = btn.getAttribute('data-status');
2290 + var newStatus = (currentStatus === 'publish') ? 'draft' : 'publish';
2291 +
2292 + var formData = new FormData();
2293 + formData.append('action', 'ka_hf_toggle_template_status');
2294 + formData.append('nonce', kaHfNonce);
2295 + formData.append('template_id', templateId);
2296 + formData.append('new_status', newStatus);
2297 +
2298 + fetch(kaHfAjaxUrl, {
2299 + method: 'POST',
2300 + body: formData
2301 + })
2302 + .then(function(response) { return response.json(); })
2303 + .then(function(data) {
2304 + if (data.success) {
2305 + // Update button text and data attribute
2306 + btn.setAttribute('data-status', newStatus);
2307 + btn.textContent = (newStatus === 'publish') ? '<?php echo esc_js(__('Disable', 'king-addons')); ?>' : '<?php echo esc_js(__('Enable', 'king-addons')); ?>';
2308 +
2309 + // Update status badge
2310 + var templateEl = document.querySelector('.ka-hf-template[data-template-id="' + templateId + '"]');
2311 + if (templateEl) {
2312 + templateEl.setAttribute('data-status', newStatus);
2313 + var statusBadge = templateEl.querySelector('.ka-hf-template-status');
2314 + if (statusBadge) {
2315 + if (newStatus === 'publish') {
2316 + statusBadge.classList.remove('is-disabled');
2317 + statusBadge.classList.add('is-enabled');
2318 + var typeLabel = templateEl.getAttribute('data-type-label') || '';
2319 + statusBadge.textContent = typeLabel || '<?php echo esc_js(__('Enabled', 'king-addons')); ?>';
2320 + } else {
2321 + statusBadge.classList.remove('is-enabled');
2322 + statusBadge.classList.add('is-disabled');
2323 + statusBadge.textContent = '<?php echo esc_js(__('Disabled', 'king-addons')); ?>';
2324 + }
2325 + }
2326 + }
2327 + } else {
2328 + alert(data.data && data.data.message ? data.data.message : '<?php echo esc_js(__('Error updating template status', 'king-addons')); ?>');
2329 + }
2330 + })
2331 + .catch(function(err) {
2332 + alert('<?php echo esc_js(__('Error updating template status', 'king-addons')); ?>');
2333 + // console.error(err);
2334 + });
2335 + });
2336 + });
2337 +
2338 + // ==========================================
2339 + // Create Modal: Show/hide specific input
2340 + // ==========================================
2341 + var displayRuleSelect = document.getElementById('ka-hf-display-rule');
2342 + var displaySpecificInput = document.getElementById('ka-hf-display-specific');
2343 +
2344 + if (displayRuleSelect && displaySpecificInput) {
2345 + displayRuleSelect.addEventListener('change', function() {
2346 + if (this.value === 'specifics') {
2347 + displaySpecificInput.style.display = 'block';
2348 + } else {
2349 + displaySpecificInput.style.display = 'none';
2350 + displaySpecificInput.value = '';
2351 + }
2352 + });
2353 + }
2354 +
2355 + if (createAddUserRoleBtn) {
2356 + createAddUserRoleBtn.addEventListener('click', function() {
2357 + if (createUserRolesContainer && typeof addUserRoleRow === 'function') {
2358 + addUserRoleRow(createUserRolesContainer, 'all', true);
2359 + }
2360 + });
2361 + }
2362 +
2363 + // ==========================================
2364 + // Conditions Popup Functionality
2365 + // ==========================================
2366 + var conditionsModal = document.getElementById('ka-hf-conditions-modal');
2367 + var conditionsCloseButtons = document.querySelectorAll('.ka-hf-conditions-close');
2368 + var conditionButtons = document.querySelectorAll('.ka-hf-open-conditions');
2369 + var saveConditionsBtn = document.getElementById('ka-hf-save-conditions');
2370 + var ruleTemplate = document.getElementById('ka-hf-rule-template');
2371 + var userRoleTemplate = document.getElementById('ka-hf-user-role-template');
2372 + var userRolesContainer = document.getElementById('ka-hf-user-roles');
2373 + var addUserRoleBtn = document.getElementById('ka-hf-add-user-role');
2374 +
2375 + var openConditionsModal = function() {
2376 + if (conditionsModal) {
2377 + conditionsModal.classList.add('is-open');
2378 + conditionsModal.setAttribute('aria-hidden', 'false');
2379 + }
2380 + };
2381 +
2382 + var closeConditionsModal = function() {
2383 + if (conditionsModal) {
2384 + conditionsModal.classList.remove('is-open');
2385 + conditionsModal.setAttribute('aria-hidden', 'true');
2386 + }
2387 + };
2388 +
2389 + // Add rule row
2390 + var addRuleRow = function(container, ruleValue, specificValue) {
2391 + var templateContent = ruleTemplate.content.cloneNode(true);
2392 + var row = templateContent.querySelector('.ka-hf-rule-row');
2393 + var select = row.querySelector('.ka-hf-rule-select');
2394 + var specificInput = row.querySelector('.ka-hf-specific-input');
2395 + var removeBtn = row.querySelector('.ka-hf-remove-rule-btn');
2396 +
2397 + if (ruleValue) {
2398 + select.value = ruleValue;
2399 + }
2400 +
2401 + // Show specific input if needed
2402 + if (ruleValue === 'specifics') {
2403 + specificInput.style.display = 'block';
2404 + if (specificValue) {
2405 + specificInput.value = specificValue;
2406 + }
2407 + }
2408 +
2409 + // Handle select change
2410 + select.addEventListener('change', function() {
2411 + if (this.value === 'specifics') {
2412 + specificInput.style.display = 'block';
2413 + } else {
2414 + specificInput.style.display = 'none';
2415 + specificInput.value = '';
2416 + }
2417 + });
2418 +
2419 + // Handle remove
2420 + removeBtn.addEventListener('click', function() {
2421 + row.remove();
2422 + });
2423 +
2424 + container.appendChild(row);
2425 + };
2426 +
2427 + // Add user role row
2428 + var addUserRoleRow = function(container, roleValue, includeNameAttr) {
2429 + if (!container || !userRoleTemplate) return;
2430 + var templateContent = userRoleTemplate.content.cloneNode(true);
2431 + var row = templateContent.querySelector('.ka-hf-user-role-row');
2432 + var select = row.querySelector('.ka-hf-user-role-select');
2433 + var removeBtn = row.querySelector('.ka-hf-remove-rule-btn');
2434 +
2435 + if (includeNameAttr) {
2436 + select.setAttribute('name', 'ka_hf_user_role[]');
2437 + }
2438 + if (roleValue) {
2439 + select.value = roleValue;
2440 + }
2441 +
2442 + removeBtn.addEventListener('click', function() {
2443 + row.remove();
2444 + });
2445 +
2446 + container.appendChild(row);
2447 + };
2448 +
2449 + // Create modal default row (after helper is defined)
2450 + if (createUserRolesContainer && createUserRolesContainer.children.length === 0) {
2451 + addUserRoleRow(createUserRolesContainer, 'all', true);
2452 + }
2453 +
2454 + // Load template data into popup
2455 + var loadConditionsData = function(templateData) {
2456 + var includeContainer = document.getElementById('ka-hf-include-rules');
2457 + var excludeContainer = document.getElementById('ka-hf-exclude-rules');
2458 + var templateIdInput = document.getElementById('ka-hf-cond-template-id');
2459 + var templateTypeSelect = document.getElementById('ka-hf-cond-template-type');
2460 +
2461 + // Clear existing rules
2462 + includeContainer.innerHTML = '';
2463 + excludeContainer.innerHTML = '';
2464 + if (userRolesContainer) {
2465 + userRolesContainer.innerHTML = '';
2466 + }
2467 +
2468 + // Set template ID
2469 + templateIdInput.value = templateData.id;
2470 +
2471 + // Set template type
2472 + if (templateTypeSelect && templateData.type) {
2473 + templateTypeSelect.value = templateData.type;
2474 + }
2475 +
2476 + // Load include rules
2477 + var includeRules = templateData.include && templateData.include.rule ? templateData.include.rule : [];
2478 + var includeSpecific = templateData.include && templateData.include.specific ? templateData.include.specific : [];
2479 +
2480 + if (includeRules.length === 0) {
2481 + addRuleRow(includeContainer, 'basic-global', '');
2482 + } else {
2483 + includeRules.forEach(function(rule, idx) {
2484 + var specificVal = (rule === 'specifics' && includeSpecific.length) ? includeSpecific.join(',') : '';
2485 + addRuleRow(includeContainer, rule, specificVal);
2486 + });
2487 + }
2488 +
2489 + // Load exclude rules
2490 + var excludeRules = templateData.exclude && templateData.exclude.rule ? templateData.exclude.rule : [];
2491 + var excludeSpecific = templateData.exclude && templateData.exclude.specific ? templateData.exclude.specific : [];
2492 +
2493 + excludeRules.forEach(function(rule, idx) {
2494 + var specificVal = (rule === 'specifics' && excludeSpecific.length) ? excludeSpecific.join(',') : '';
2495 + addRuleRow(excludeContainer, rule, specificVal);
2496 + });
2497 +
2498 + // Load user roles (rows)
2499 + var userRoles = templateData.userRoles || [];
2500 + if (!Array.isArray(userRoles) || userRoles.length === 0) {
2501 + userRoles = ['all'];
2502 + }
2503 + userRoles.forEach(function(role) {
2504 + addUserRoleRow(userRolesContainer, role, false);
2505 + });
2506 + };
2507 +
2508 + // Condition button click handlers
2509 + conditionButtons.forEach(function(btn) {
2510 + btn.addEventListener('click', function(e) {
2511 + e.preventDefault();
2512 + e.stopPropagation();
2513 + var templateData = JSON.parse(btn.getAttribute('data-template'));
2514 + loadConditionsData(templateData);
2515 + openConditionsModal();
2516 + });
2517 + });
2518 +
2519 + // Add rule buttons
2520 + document.querySelectorAll('.ka-hf-add-rule-btn').forEach(function(btn) {
2521 + btn.addEventListener('click', function() {
2522 + var ruleType = btn.getAttribute('data-rule-type');
2523 + var container = document.getElementById('ka-hf-' + ruleType + '-rules');
2524 + addRuleRow(container, 'basic-global', '');
2525 + });
2526 + });
2527 +
2528 + if (addUserRoleBtn) {
2529 + addUserRoleBtn.addEventListener('click', function() {
2530 + addUserRoleRow(userRolesContainer, 'all', false);
2531 + });
2532 + }
2533 +
2534 + // Close buttons
2535 + conditionsCloseButtons.forEach(function(btn) {
2536 + btn.addEventListener('click', closeConditionsModal);
2537 + });
2538 +
2539 + // Backdrop click
2540 + if (conditionsModal) {
2541 + conditionsModal.addEventListener('click', function(e) {
2542 + if (e.target === conditionsModal) {
2543 + closeConditionsModal();
2544 + }
2545 + });
2546 + }
2547 +
2548 + // Save conditions via AJAX
2549 + if (saveConditionsBtn) {
2550 + saveConditionsBtn.addEventListener('click', function() {
2551 + var savingOverlay = document.getElementById('ka-hf-conditions-saving');
2552 + savingOverlay.style.display = 'flex';
2553 +
2554 + var templateId = document.getElementById('ka-hf-cond-template-id').value;
2555 + var templateType = document.getElementById('ka-hf-cond-template-type').value;
2556 +
2557 + // Collect user roles
2558 + var selectedRoles = [];
2559 + document.querySelectorAll('#ka-hf-user-roles .ka-hf-user-role-select').forEach(function(sel) {
2560 + if (sel && sel.value) {
2561 + selectedRoles.push(sel.value);
2562 + }
2563 + });
2564 + // De-dupe and default
2565 + selectedRoles = Array.from(new Set(selectedRoles));
2566 + if (selectedRoles.length === 0) {
2567 + selectedRoles = ['all'];
2568 + }
2569 + if (selectedRoles.indexOf('all') !== -1) {
2570 + selectedRoles = ['all'];
2571 + }
2572 +
2573 + // Collect include rules
2574 + var includeRules = [];
2575 + document.querySelectorAll('#ka-hf-include-rules .ka-hf-rule-row').forEach(function(row) {
2576 + var rule = row.querySelector('.ka-hf-rule-select').value;
2577 + var specific = row.querySelector('.ka-hf-specific-input').value;
2578 + includeRules.push({ rule: rule, specific: specific });
2579 + });
2580 +
2581 + // Collect exclude rules
2582 + var excludeRules = [];
2583 + document.querySelectorAll('#ka-hf-exclude-rules .ka-hf-rule-row').forEach(function(row) {
2584 + var rule = row.querySelector('.ka-hf-rule-select').value;
2585 + var specific = row.querySelector('.ka-hf-specific-input').value;
2586 + excludeRules.push({ rule: rule, specific: specific });
2587 + });
2588 +
2589 + // Build form data
2590 + var formData = new FormData();
2591 + formData.append('action', 'ka_hf_save_conditions');
2592 + formData.append('nonce', kaHfNonce);
2593 + formData.append('template_id', templateId);
2594 + formData.append('template_type', templateType);
2595 +
2596 + // Append multiple user roles
2597 + selectedRoles.forEach(function(role, idx) {
2598 + formData.append('user_roles[' + idx + ']', role);
2599 + });
2600 +
2601 + includeRules.forEach(function(rule, idx) {
2602 + formData.append('include_rules[' + idx + '][rule]', rule.rule);
2603 + formData.append('include_rules[' + idx + '][specific]', rule.specific);
2604 + });
2605 +
2606 + excludeRules.forEach(function(rule, idx) {
2607 + formData.append('exclude_rules[' + idx + '][rule]', rule.rule);
2608 + formData.append('exclude_rules[' + idx + '][specific]', rule.specific);
2609 + });
2610 +
2611 + fetch(kaHfAjaxUrl, {
2612 + method: 'POST',
2613 + body: formData
2614 + })
2615 + .then(function(response) { return response.json(); })
2616 + .then(function(data) {
2617 + savingOverlay.style.display = 'none';
2618 + if (data.success) {
2619 + closeConditionsModal();
2620 + // Reload page to show updated conditions
2621 + window.location.reload();
2622 + } else {
2623 + alert(data.data && data.data.message ? data.data.message : 'Error saving conditions');
2624 + }
2625 + })
2626 + .catch(function(err) {
2627 + savingOverlay.style.display = 'none';
2628 + alert('Error saving conditions');
2629 + // console.error(err);
2630 + });
2631 + });
2632 + }
2633 + });
2634 + </script>
2635 + <?php
2636 + }
2637 +
2638 + public function disableScreenOptions($show_screen, $screen)
2639 + {
2640 + if ($screen->id === 'edit-king-addons-el-hf') {
2641 + return false;
2642 + }
2643 + return $show_screen;
2644 + }
2645 +
2646 + function king_addons_el_hf_get_posts_by_query()
2647 + {
2648 + // Security fix: Add authorization check
2649 + if (!current_user_can('edit_posts')) {
2650 + wp_send_json_error('Insufficient permissions');
2651 + return;
2652 + }
2653 +
2654 + check_ajax_referer('king-addons-el-hf-get-posts-by-query', 'nonce');
2655 +
2656 + $search_string = isset($_POST['q']) ? sanitize_text_field($_POST['q']) : '';
2657 + $result = array();
2658 +
2659 + $args = array(
2660 + 'public' => true,
2661 + '_builtin' => false,
2662 + );
2663 +
2664 + $output = 'names';
2665 + $operator = 'and';
2666 + $post_types = get_post_types($args, $output, $operator);
2667 +
2668 + unset($post_types['elementor-hf']);
2669 +
2670 + $post_types['Posts'] = 'post';
2671 + $post_types['Pages'] = 'page';
2672 +
2673 + foreach ($post_types as $key => $post_type) {
2674 + $data = array();
2675 +
2676 + add_filter('posts_search', array($this, 'search_only_titles'), 10, 2);
2677 +
2678 + $query = new WP_Query(
2679 + array(
2680 + 's' => $search_string,
2681 + 'post_type' => $post_type,
2682 + 'posts_per_page' => -1,
2683 + )
2684 + );
2685 +
2686 + if ($query->have_posts()) {
2687 + while ($query->have_posts()) {
2688 + $query->the_post();
2689 + $title = get_the_title();
2690 + $title .= (0 != $query->post->post_parent) ? ' (' . get_the_title($query->post->post_parent) . ')' : '';
2691 + $id = get_the_id();
2692 + $data[] = array(
2693 + 'id' => 'post-' . $id,
2694 + 'text' => $title,
2695 + );
2696 + }
2697 + }
2698 +
2699 + if (is_array($data) && !empty($data)) {
2700 + $result[] = array(
2701 + 'text' => $key,
2702 + 'children' => $data,
2703 + );
2704 + }
2705 + }
2706 +
2707 + wp_reset_postdata();
2708 +
2709 + $args = array(
2710 + 'public' => true,
2711 + );
2712 +
2713 + $output = 'objects';
2714 + $taxonomies = get_taxonomies($args, $output, $operator);
2715 +
2716 + foreach ($taxonomies as $taxonomy) {
2717 + $terms = get_terms(
2718 + $taxonomy->name,
2719 + array(
2720 + 'orderby' => 'count',
2721 + 'hide_empty' => 0,
2722 + 'name__like' => $search_string,
2723 + )
2724 + );
2725 +
2726 + $data = array();
2727 +
2728 + $label = ucwords($taxonomy->label);
2729 +
2730 + if (!empty($terms)) {
2731 + foreach ($terms as $term) {
2732 +
2733 + $data[] = array(
2734 + 'id' => 'tax-' . $term->term_id,
2735 + 'text' => $term->name . ' archive page',
2736 + );
2737 +
2738 + $data[] = array(
2739 + 'id' => 'tax-' . $term->term_id . '-single-' . $taxonomy->name,
2740 + 'text' => 'All singulars from ' . $term->name,
2741 + );
2742 + }
2743 + }
2744 +
2745 + if (is_array($data) && !empty($data)) {
2746 + $result[] = array(
2747 + 'text' => $label,
2748 + 'children' => $data,
2749 + );
2750 + }
2751 + }
2752 +
2753 + wp_send_json($result);
2754 + }
2755 +
2756 + public function initialize_options()
2757 + {
2758 + self::$user_selection = self::get_user_selections();
2759 + self::$location_selection = self::getLocationSelections();
2760 + }
2761 +
2762 + public function renderAdminCustomHeader()
2763 + {
2764 + $current_screen = get_current_screen()->id;
2765 + if ($current_screen !== 'edit-king-addons-el-hf'
2766 + && $current_screen !== 'header-footer_page_king-addons-el-hf-settings') {
2767 + return;
2768 + }
2769 +
2770 + ?>
2771 + <div class="king-addons-pb-settings-page-header">
2772 + <h1><?php esc_html_e('Elementor Header & Footer Builder', 'king-addons'); ?></h1>
2773 + <p>
2774 + <?php esc_html_e('Create fully customizable headers and footers with display conditions to control where they appear', 'king-addons'); ?>
2775 + </p>
2776 + <div class="king-addons-pb-preview-buttons">
2777 + <a href="<?php echo admin_url('post-new.php?post_type=king-addons-el-hf'); ?>">
2778 + <div class="king-addons-pb-user-template">
2779 + <span><?php esc_html_e('Create New', 'king-addons'); ?></span>
2780 + <span class="plus-icon">+</span>
2781 + </div>
2782 + </a>
2783 + <?php if (!king_addons_freemius()->can_use_premium_code__premium_only()): ?>
2784 + <div class="kng-promo-btn-wrap">
2785 + <a href="https://kingaddons.com/pricing/?utm_source=king-addons-hf-builder" target="_blank">
2786 + <div class="kng-promo-btn-txt">
2787 + <?php esc_html_e('Unlock Premium Features & 650+ Templates Today!', 'king-addons'); ?>
2788 + </div>
2789 + <img width="16px"
2790 + src="<?php echo esc_url(KING_ADDONS_URL) . 'includes/admin/img/share-v2.svg'; ?>"
2791 + alt="<?php echo esc_html__('Open link in the new tab', 'king-addons'); ?>">
2792 + </a>
2793 + </div>
2794 + <?php endif; ?>
2795 + </div>
2796 + </div>
2797 + <?php
2798 +
2799 + $counts = wp_count_posts('king-addons-el-hf');
2800 + $total = (int)$counts->publish + (int)$counts->draft;
2801 +
2802 + if (0 === $total) {
2803 + echo '<div class="notice notice-info">';
2804 + echo '<p>';
2805 + echo esc_html__("Create the first header or footer by clicking the 'Create New' button above.", 'king addons');
2806 + echo '</p>';
2807 + echo '</div>';
2808 + }
2809 +
2810 + }
2811 +
2812 + function addPostType(): void
2813 + {
2814 + if (!current_user_can('manage_options')) {
2815 + return;
2816 + }
2817 +
2818 + $labels = [
2819 + 'name' => esc_html__('Elementor Header & Footer Builder', 'king-addons'),
2820 + 'singular_name' => esc_html__('Elementor Header & Footer Builder', 'king-addons'),
2821 + 'menu_name' => esc_html__('Elementor Header & Footer Builder', 'king-addons'),
2822 + 'name_admin_bar' => esc_html__('Elementor Header & Footer Builder', 'king-addons'),
2823 + 'add_new' => esc_html__('Add New', 'king-addons'),
2824 + 'add_new_item' => esc_html__('Add New', 'king-addons'),
2825 + 'new_item' => esc_html__('New Template', 'king-addons'),
2826 + 'edit_item' => esc_html__('Edit Template', 'king-addons'),
2827 + 'view_item' => esc_html__('View Template', 'king-addons'),
2828 + 'all_items' => esc_html__('All Templates', 'king-addons'),
2829 + 'search_items' => esc_html__('Search Templates', 'king-addons'),
2830 + 'parent_item_colon' => esc_html__('Parent Templates:', 'king-addons'),
2831 + 'not_found' => esc_html__('No Templates found.', 'king-addons'),
2832 + 'not_found_in_trash' => esc_html__('No Templates found in Trash.', 'king-addons'),
2833 + ];
2834 +
2835 + $args = [
2836 + 'labels' => $labels,
2837 + 'public' => true,
2838 + 'show_ui' => true,
2839 + 'show_in_menu' => false,
2840 + 'show_in_nav_menus' => false,
2841 + 'exclude_from_search' => true,
2842 + 'capability_type' => 'post',
2843 + 'hierarchical' => false,
2844 + 'menu_icon' => 'dashicons-editor-kitchensink',
2845 + 'supports' => ['title', 'editor', 'thumbnail', 'elementor'],
2846 + 'show_in_rest' => true,
2847 + ];
2848 +
2849 + register_post_type('king-addons-el-hf', $args);
2850 +
2851 + if (false === get_option('king_addons_HFB_flushed_rewrite_rules')) {
2852 + add_option('king_addons_HFB_flushed_rewrite_rules', true);
2853 + flush_rewrite_rules();
2854 + }
2855 + }
2856 +
2857 + function registerMetabox()
2858 + {
2859 + add_meta_box(
2860 + 'king-addons-el-hf-meta-box',
2861 + esc_html__('Elementor Header & Footer Builder Options', 'king-addons'),
2862 + [$this, 'renderMetabox'],
2863 + 'king-addons-el-hf',
2864 + 'normal',
2865 + 'high'
2866 + );
2867 + }
2868 +
2869 + function renderMetabox($post)
2870 + {
2871 + $values = get_post_custom($post->ID);
2872 + $template_type = isset($values['king_addons_el_hf_template_type']) ? esc_attr(sanitize_text_field($values['king_addons_el_hf_template_type'][0])) : '';
2873 + $display_on_canvas = isset($values['king-addons-el-hf-display-on-canvas']);
2874 +
2875 + wp_nonce_field('king_addons_el_hf_meta_nounce', 'king_addons_el_hf_meta_nounce');
2876 + ?>
2877 + <table class="king-addons-el-hf-options-table widefat">
2878 + <tbody>
2879 + <tr class="king-addons-el-hf-options-row type-of-template">
2880 + <td class="king-addons-el-hf-options-row-heading">
2881 + <label for="king_addons_el_hf_template_type"><strong><?php esc_html_e('Type of Template', 'king-addons'); ?></strong></label>
2882 + </td>
2883 + <td class="king-addons-el-hf-options-row-content">
2884 + <select name="king_addons_el_hf_template_type" id="king_addons_el_hf_template_type">
2885 + <option value="king_addons_el_hf_not_selected" <?php selected($template_type, ''); ?>><?php esc_html_e('Select Option', 'king-addons'); ?></option>
2886 + <option value="king_addons_el_hf_type_header" <?php selected($template_type, 'king_addons_el_hf_type_header'); ?>><?php esc_html_e('Header', 'king-addons'); ?></option>
2887 + <option value="king_addons_el_hf_type_footer" <?php selected($template_type, 'king_addons_el_hf_type_footer'); ?>><?php esc_html_e('Footer', 'king-addons'); ?></option>
2888 + </select>
2889 + </td>
2890 + </tr>
2891 + <?php
2892 + $this->display_rules_tab();
2893 +
2894 + ?>
2895 + <tr class="king-addons-el-hf-options-row enable-for-canvas">
2896 + <td class="king-addons-el-hf-options-row-heading">
2897 + <label for="king-addons-el-hf-display-on-canvas">
2898 + <strong><?php esc_html_e('Enable Layout for Elementor Canvas Template?', 'king-addons'); ?></strong>
2899 + </label>
2900 + <p><?php esc_html_e('Enabling this option will display this layout on pages using Elementor Canvas Template', 'king-addons'); ?></p>
2901 + </td>
2902 + <td class="king-addons-el-hf-options-row-content">
2903 + <input type="checkbox" id="king-addons-el-hf-display-on-canvas"
2904 + name="king-addons-el-hf-display-on-canvas"
2905 + value="1" <?php checked($display_on_canvas); ?> />
2906 + </td>
2907 + </tr>
2908 + </tbody>
2909 + </table>
2910 + <?php
2911 + }
2912 +
2913 +
2914 + public function admin_styles()
2915 + {
2916 + wp_enqueue_script('king-addons-el-hf-select2', KING_ADDONS_URL . 'includes/extensions/Header_Footer_Builder/select2.js', array('jquery'), KING_ADDONS_VERSION, true);
2917 +
2918 + wp_register_script(
2919 + 'king-addons-el-hf-target-rule',
2920 + KING_ADDONS_URL . 'includes/extensions/Header_Footer_Builder/conditions-target.js',
2921 + array(
2922 + 'jquery',
2923 + 'king-addons-el-hf-select2',
2924 + ),
2925 + KING_ADDONS_VERSION,
2926 + true
2927 + );
2928 +
2929 + wp_enqueue_script('king-addons-el-hf-target-rule');
2930 +
2931 + wp_register_script(
2932 + 'king-addons-el-hf-user-role',
2933 + KING_ADDONS_URL . 'includes/extensions/Header_Footer_Builder/conditions-user.js',
2934 + array(
2935 + 'jquery',
2936 + ),
2937 + KING_ADDONS_VERSION,
2938 + true
2939 + );
2940 +
2941 + wp_enqueue_script('king-addons-el-hf-user-role');
2942 +
2943 + wp_register_style('king-addons-el-hf-select2', KING_ADDONS_URL . 'includes/extensions/Header_Footer_Builder/select2.css', '', KING_ADDONS_VERSION);
2944 + wp_enqueue_style('king-addons-el-hf-select2');
2945 + wp_register_style('king-addons-el-hf-target-rule', KING_ADDONS_URL . 'includes/extensions/Header_Footer_Builder/conditions.css', '', KING_ADDONS_VERSION);
2946 + wp_enqueue_style('king-addons-el-hf-target-rule');
2947 + wp_enqueue_script('king-addons-el-hf-script', KING_ADDONS_URL . 'includes/extensions/Header_Footer_Builder/admin.js', array('jquery'), KING_ADDONS_VERSION);
2948 +
2949 + $localize_vars = array(
2950 + 'please_enter' => __('Please enter', 'king-addons'),
2951 + 'please_delete' => __('Please delete', 'king-addons'),
2952 + 'more_char' => __('or more characters', 'king-addons'),
2953 + 'character' => __('character', 'king-addons'),
2954 + 'loading' => __('Loading more results…', 'king-addons'),
2955 + 'only_select' => __('You can only select', 'king-addons'),
2956 + 'item' => __('item', 'king-addons'),
2957 + 'char_s' => __('s', 'king-addons'),
2958 + 'no_result' => __('No results found', 'king-addons'),
2959 + 'searching' => __('Searching…', 'king-addons'),
2960 + 'not_loader' => __('The results could not be loaded.', 'king-addons'),
2961 + 'search' => __('Search pages / post / categories', 'king-addons'),
2962 + 'ajax_nonce' => wp_create_nonce('king-addons-el-hf-get-posts-by-query'),
2963 + );
2964 + wp_localize_script('king-addons-el-hf-select2', 'kngRules', $localize_vars);
2965 +
2966 + }
2967 +
2968 + public function display_rules_tab()
2969 + {
2970 + $this->admin_styles();
2971 + $include_locations = get_post_meta(get_the_id(), 'king_addons_el_hf_target_include_locations', true);
2972 + $exclude_locations = get_post_meta(get_the_id(), 'king_addons_el_hf_target_exclude_locations', true);
2973 + $users = get_post_meta(get_the_id(), 'king_addons_el_hf_target_user_roles', true);
2974 + ?>
2975 + <tr class="king-addons-el-hf-target-rules-row king-addons-el-hf-options-row">
2976 + <td class="king-addons-el-hf-target-rules-row-heading king-addons-el-hf-options-row-heading">
2977 + <label><strong><?php esc_html_e('Display On', 'king-addons'); ?></strong></label>
2978 + <p><?php esc_html_e('Add locations for where this template should appear', 'king-addons'); ?></p>
2979 + </td>
2980 + <td class="king-addons-el-hf-target-rules-row-content king-addons-el-hf-options-row-content">
2981 + <?php
2982 + self::target_rule_settings_field(
2983 + 'king-addons-el-hf-target-rules-location',
2984 + [
2985 + 'title' => __('Display Rules', 'king-addons'),
2986 + 'value' => '[{"type":"basic-global","specific":null}]',
2987 + 'tags' => 'site,enable,target,pages',
2988 + 'rule_type' => 'display',
2989 + 'add_rule_label' => __('Add Display Rule', 'king-addons'),
2990 + ],
2991 + $include_locations
2992 + );
2993 + ?>
2994 + </td>
2995 + </tr>
2996 + <tr class="king-addons-el-hf-target-rules-row king-addons-el-hf-options-row">
2997 + <td class="king-addons-el-hf-target-rules-row-heading king-addons-el-hf-options-row-heading">
2998 + <label><strong><?php esc_html_e('Do Not Display On', 'king-addons'); ?></strong></label>
2999 + <p><?php esc_html_e('Add locations for where this template should not appear', 'king-addons'); ?></p>
3000 + </td>
3001 + <td class="king-addons-el-hf-target-rules-row-content king-addons-el-hf-options-row-content">
3002 + <?php
3003 + self::target_rule_settings_field(
3004 + 'king-addons-el-hf-target-rules-exclusion',
3005 + [
3006 + 'title' => __('Exclude On', 'king-addons'),
3007 + 'value' => '[]',
3008 + 'tags' => 'site,enable,target,pages',
3009 + 'add_rule_label' => __('Add Exclusion Rule', 'king-addons'),
3010 + 'rule_type' => 'exclude',
3011 + ],
3012 + $exclude_locations
3013 + );
3014 + ?>
3015 + </td>
3016 + </tr>
3017 + <tr class="king-addons-el-hf-target-rules-row king-addons-el-hf-options-row">
3018 + <td class="king-addons-el-hf-target-rules-row-heading king-addons-el-hf-options-row-heading">
3019 + <label><strong><?php esc_html_e('User Roles', 'king-addons'); ?></strong></label>
3020 + <p><?php esc_html_e('Display custom template based on user role', 'king-addons'); ?></p>
3021 + </td>
3022 + <td class="king-addons-el-hf-target-rules-row-content king-addons-el-hf-options-row-content">
3023 + <?php
3024 + self::target_user_role_settings_field(
3025 + 'king-addons-el-hf-target-rules-users',
3026 + [
3027 + 'title' => __('Users', 'king-addons'),
3028 + 'value' => '[]',
3029 + 'tags' => 'site,enable,target,pages',
3030 + 'add_rule_label' => __('Add User Rule', 'king-addons'),
3031 + ],
3032 + $users
3033 + );
3034 + ?>
3035 + </td>
3036 + </tr>
3037 + <?php
3038 + }
3039 +
3040 + public static function get_user_selections()
3041 + {
3042 + $selection_options = array(
3043 + 'basic' => array(
3044 + 'label' => __('Basic', 'king-addons'),
3045 + 'value' => array(
3046 + 'all' => __('All', 'king-addons'),
3047 + 'logged-in' => __('Logged In', 'king-addons'),
3048 + 'logged-out' => __('Logged Out', 'king-addons'),
3049 + ),
3050 + ),
3051 +
3052 + 'advanced' => array(
3053 + 'label' => __('Advanced', 'king-addons'),
3054 + 'value' => array(),
3055 + ),
3056 + );
3057 +
3058 + /* User roles */
3059 + $roles = get_editable_roles();
3060 +
3061 + foreach ($roles as $slug => $data) {
3062 + $selection_options['advanced']['value'][$slug] = $data['name'];
3063 + }
3064 +
3065 + /**
3066 + * Filter options displayed in the user select field of Display conditions.
3067 + *
3068 + * @since 1.5.0
3069 + */
3070 + return apply_filters('king-addons-el-hf_user_roles_list', $selection_options);
3071 + }
3072 +
3073 + public static function target_user_role_settings_field($name, $settings, $value)
3074 + {
3075 + $input_name = $name;
3076 + $add_rule_label = $settings['add_rule_label'] ?? __('Add Rule', 'king-addons');
3077 + $saved_values = $value;
3078 + $output = '';
3079 +
3080 + if (!isset(self::$user_selection) || empty(self::$user_selection)) {
3081 + self::$user_selection = self::get_user_selections();
3082 + }
3083 + $selection_options = self::$user_selection;
3084 +
3085 + $output .= '<script type="text/html" id="tmpl-king-addons-el-hf-user-role-condition">';
3086 + $output .= '<div class="king-addons-el-hf-user-role-condition king-addons-el-hf-user-role-{{data.id}}" data-rule="{{data.id}}" >';
3087 + $output .= '<span class="user_role-condition-delete dashicons dashicons-dismiss"></span>';
3088 +
3089 + $output .= '<div class="user_role-condition-wrap" >';
3090 + $output .= '<select name="' . esc_attr($input_name) . '[{{data.id}}]" class="user_role-condition form-control king-addons-el-hf-input">';
3091 + $output .= '<option value="">' . __('Select', 'king-addons') . '</option>';
3092 +
3093 + foreach ($selection_options as $group_data) {
3094 + $output .= '<optgroup label="' . $group_data['label'] . '">';
3095 + foreach ($group_data['value'] as $opt_key => $opt_value) {
3096 + $output .= '<option value="' . $opt_key . '">' . $opt_value . '</option>';
3097 + }
3098 + $output .= '</optgroup>';
3099 + }
3100 + $output .= '</select>';
3101 + $output .= '</div>';
3102 + $output .= '</div> <!-- king-addons-el-hf-user-role-condition -->';
3103 + $output .= '</script>';
3104 +
3105 + /** @noinspection PhpConditionAlreadyCheckedInspection */
3106 + if (!is_array($saved_values) || (is_array($saved_values) && empty($saved_values))) {
3107 + $saved_values = array();
3108 + $saved_values[0] = '';
3109 + }
3110 +
3111 + $index = 0;
3112 +
3113 + $output .= '<div class="king-addons-el-hf-user-role-wrapper king-addons-el-hf-user-role-display-on-wrap" data-type="display">';
3114 + $output .= '<div class="king-addons-el-hf-user-role-selector-wrapper king-addons-el-hf-user-role-display-on">';
3115 + $output .= '<div class="user_role-builder-wrap">';
3116 + foreach ($saved_values as $index => $data) {
3117 + $output .= '<div class="king-addons-el-hf-user-role-condition king-addons-el-hf-user-role-' . $index . '" data-rule="' . $index . '" >';
3118 + $output .= '<span class="user_role-condition-delete dashicons dashicons-dismiss"></span>';
3119 + /* Condition Selection */
3120 + $output .= '<div class="user_role-condition-wrap" >';
3121 + $output .= '<select name="' . esc_attr($input_name) . '[' . $index . ']" class="user_role-condition form-control king-addons-el-hf-input">';
3122 + $output .= '<option value="">' . __('Select', 'king-addons') . '</option>';
3123 +
3124 + foreach ($selection_options as $group_data) {
3125 + $output .= '<optgroup label="' . $group_data['label'] . '">';
3126 + foreach ($group_data['value'] as $opt_key => $opt_value) {
3127 + $output .= '<option value="' . $opt_key . '" ' . selected($data, $opt_key, false) . '>' . $opt_value . '</option>';
3128 + }
3129 + $output .= '</optgroup>';
3130 + }
3131 + $output .= '</select>';
3132 + $output .= '</div>';
3133 + $output .= '</div> <!-- king-addons-el-hf-user-role-condition -->';
3134 + }
3135 + $output .= '</div>';
3136 + /* Add new rule */
3137 + $output .= '<div class="user_role-add-rule-wrap">';
3138 + $output .= '<a href="#" class="button" data-rule-id="' . absint($index) . '">' . $add_rule_label . '</a>';
3139 + $output .= '</div>';
3140 + $output .= '</div>';
3141 + $output .= '</div>';
3142 +
3143 + echo $output;
3144 + }
3145 +
3146 + public static function target_rule_settings_field($name, $settings, $value)
3147 + {
3148 + $input_name = $name;
3149 + $rule_type = $settings['rule_type'] ?? 'target_rule';
3150 + $add_rule_label = $settings['add_rule_label'] ?? __('Add Rule', 'king-addons');
3151 + $saved_values = $value;
3152 + $output = '';
3153 +
3154 + if (isset(self::$location_selection) || empty(self::$location_selection)) {
3155 + self::$location_selection = self::getLocationSelections();
3156 + }
3157 + $selection_options = self::$location_selection;
3158 +
3159 + $output .= '<script type="text/html" id="tmpl-king-addons-el-hf-target-rule-' . $rule_type . '-condition">';
3160 +
3161 + $output .= '<div class="king-addons-el-hf-target-rule-condition king-addons-el-hf-target-rule-{{data.id}}" data-rule="{{data.id}}" >';
3162 + $output .= '<span class="target_rule-condition-delete dashicons dashicons-dismiss"></span>';
3163 + $output .= '<div class="target_rule-condition-wrap" >';
3164 +
3165 + $output .= '<select name="' . esc_attr($input_name) . '[rule][{{data.id}}]" class="target_rule-condition form-control king-addons-el-hf-input">';
3166 + $output .= '<option value="">' . __('Select', 'king-addons') . '</option>';
3167 +
3168 + foreach ($selection_options as $group_data) {
3169 + $output .= '<optgroup label="' . $group_data['label'] . '">';
3170 + foreach ($group_data['value'] as $opt_key => $opt_value) {
3171 + $output .= '<option value="' . $opt_key . '">' . $opt_value . '</option>';
3172 + }
3173 + $output .= '</optgroup>';
3174 + }
3175 + $output .= '</select>';
3176 +
3177 + $output .= '</div>';
3178 + $output .= '</div> <!-- king-addons-el-hf-target-rule-condition -->';
3179 +
3180 + $output .= '<div class="target_rule-specific-page-wrap" style="display:none">';
3181 + $output .= '<select name="' . esc_attr($input_name) . '[specific][]" class="target-rule-select2 target_rule-specific-page form-control king-addons-el-hf-input " multiple="multiple">';
3182 + $output .= '</select>';
3183 + $output .= '</div>';
3184 +
3185 + $output .= '</script>';
3186 +
3187 + $output .= '<div class="king-addons-el-hf-target-rule-wrapper king-addons-el-hf-target-rule-' . $rule_type . '-on-wrap" data-type="' . $rule_type . '">';
3188 + $output .= '<div class="king-addons-el-hf-target-rule-selector-wrapper king-addons-el-hf-target-rule-' . $rule_type . '-on">';
3189 + $output .= self::generate_target_rule_selector($rule_type, $selection_options, $input_name, $saved_values, $add_rule_label);
3190 + $output .= '</div>';
3191 + $output .= '</div>';
3192 +
3193 + echo $output;
3194 + }
3195 +
3196 + public static function generate_target_rule_selector($type, $selection_options, $input_name, $saved_values, $add_rule_label)
3197 + {
3198 + $output = '<div class="target_rule-builder-wrap">';
3199 +
3200 + /** @noinspection PhpConditionAlreadyCheckedInspection */
3201 + if (!is_array($saved_values) || (is_array($saved_values) && empty($saved_values))) {
3202 + $saved_values = array();
3203 + $saved_values['rule'][0] = '';
3204 + $saved_values['specific'][0] = '';
3205 + }
3206 +
3207 + $index = 0;
3208 + if (is_array($saved_values) && is_array($saved_values['rule'])) {
3209 + foreach ($saved_values['rule'] as $index => $data) {
3210 + $output .= '<div class="king-addons-el-hf-target-rule-condition king-addons-el-hf-target-rule-' . $index . '" data-rule="' . $index . '" >';
3211 +
3212 + $output .= '<span class="target_rule-condition-delete dashicons dashicons-dismiss"></span>';
3213 + $output .= '<div class="target_rule-condition-wrap" >';
3214 + $output .= '<select name="' . esc_attr($input_name) . '[rule][' . $index . ']" class="target_rule-condition form-control king-addons-el-hf-input">';
3215 + $output .= '<option value="">' . __('Select', 'king-addons') . '</option>';
3216 +
3217 + foreach ($selection_options as $group_data) {
3218 + $output .= '<optgroup label="' . $group_data['label'] . '">';
3219 + foreach ($group_data['value'] as $opt_key => $opt_value) {
3220 +
3221 + $selected = '';
3222 +
3223 + if ($data == $opt_key) {
3224 + $selected = 'selected="selected"';
3225 + }
3226 +
3227 + $output .= '<option value="' . $opt_key . '" ' . $selected . '>' . $opt_value . '</option>';
3228 + }
3229 + $output .= '</optgroup>';
3230 + }
3231 + $output .= '</select>';
3232 + $output .= '</div>';
3233 +
3234 + $output .= '</div>';
3235 +
3236 + $output .= '<div class="target_rule-specific-page-wrap" style="display:none">';
3237 + $output .= '<select name="' . esc_attr($input_name) . '[specific][]" class="target-rule-select2 target_rule-specific-page form-control king-addons-el-hf-input " multiple="multiple">';
3238 +
3239 + if ('specifics' == $data && isset($saved_values['specific']) && null != $saved_values['specific'] && is_array($saved_values['specific'])) {
3240 + foreach ($saved_values['specific'] as $sel_value) {
3241 +
3242 + if (strpos($sel_value, 'post-') !== false) {
3243 + $post_id = (int)str_replace('post-', '', $sel_value);
3244 + $post_title = get_the_title($post_id);
3245 + $output .= '<option value="post-' . $post_id . '" selected="selected" >' . $post_title . '</option>';
3246 + }
3247 +
3248 + if (strpos($sel_value, 'tax-') !== false) {
3249 + $tax_data = explode('-', $sel_value);
3250 +
3251 + $tax_id = (int)str_replace('tax-', '', $sel_value);
3252 + $term = get_term($tax_id);
3253 + $term_name = '';
3254 +
3255 + if (!is_wp_error($term)) {
3256 + $term_taxonomy = ucfirst(str_replace('_', ' ', $term->taxonomy));
3257 +
3258 + if (isset($tax_data[2]) && 'single' === $tax_data[2]) {
3259 + $term_name = 'All singulars from ' . $term->name;
3260 + } else {
3261 + $term_name = $term->name . ' - ' . $term_taxonomy;
3262 + }
3263 + }
3264 +
3265 + $output .= '<option value="' . $sel_value . '" selected="selected" >' . $term_name . '</option>';
3266 + }
3267 + }
3268 + }
3269 + $output .= '</select>';
3270 + $output .= '</div>';
3271 + }
3272 + }
3273 +
3274 + $output .= '</div>';
3275 +
3276 + $output .= '<div class="target_rule-add-rule-wrap">';
3277 + $output .= '<a href="#" class="button" data-rule-id="' . absint($index) . '" data-rule-type="' . $type . '">' . $add_rule_label . '</a>';
3278 + $output .= '</div>';
3279 +
3280 + if ('display' == $type) {
3281 + $output .= '<div class="target_rule-add-exclusion-rule">';
3282 + $output .= '<a href="#" class="button">' . __('Add Exclusion Rule', 'king-addons') . '</a>';
3283 + $output .= '</div>';
3284 + }
3285 +
3286 + return $output;
3287 + }
3288 +
3289 + function saveMetaboxData($post_id)
3290 + {
3291 + if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
3292 + return;
3293 + }
3294 +
3295 + if (!isset($_POST['king_addons_el_hf_meta_nounce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['king_addons_el_hf_meta_nounce'])), 'king_addons_el_hf_meta_nounce')) {
3296 + return;
3297 + }
3298 +
3299 + if (!current_user_can('edit_posts')) {
3300 + return;
3301 + }
3302 +
3303 + if (!isset($_POST['king-addons-el-hf-target-rules-location'])) {
3304 + $target_locations = array(
3305 + 'rule' => array('basic-global'),
3306 + 'specific' => array(),
3307 + );
3308 + } else {
3309 + $target_locations = self::getFormatRuleValue($_POST, 'king-addons-el-hf-target-rules-location');
3310 + if (empty($target_locations)) {
3311 + $target_locations = array(
3312 + 'rule' => array('basic-global'),
3313 + 'specific' => array(),
3314 + );
3315 + }
3316 + }
3317 +
3318 + $target_exclusion = self::getFormatRuleValue($_POST, 'king-addons-el-hf-target-rules-exclusion');
3319 + $target_users = [];
3320 +
3321 + if (isset($_POST['king-addons-el-hf-target-rules-users'])) {
3322 + $target_users = array_map('sanitize_text_field', wp_unslash($_POST['king-addons-el-hf-target-rules-users']));
3323 + }
3324 +
3325 + update_post_meta($post_id, 'king_addons_el_hf_target_include_locations', $target_locations);
3326 + update_post_meta($post_id, 'king_addons_el_hf_target_exclude_locations', $target_exclusion);
3327 + update_post_meta($post_id, 'king_addons_el_hf_target_user_roles', $target_users);
3328 +
3329 + if (isset($_POST['king_addons_el_hf_template_type'])) {
3330 + update_post_meta($post_id, 'king_addons_el_hf_template_type', sanitize_text_field(wp_unslash($_POST['king_addons_el_hf_template_type'])));
3331 + }
3332 +
3333 + if (isset($_POST['king-addons-el-hf-display-on-canvas'])) {
3334 + update_post_meta($post_id, 'king-addons-el-hf-display-on-canvas', sanitize_text_field(wp_unslash($_POST['king-addons-el-hf-display-on-canvas'])));
3335 + } else {
3336 + delete_post_meta($post_id, 'king-addons-el-hf-display-on-canvas');
3337 + }
3338 + }
3339 +
3340 + function setCompatibility()
3341 + {
3342 + $template = get_template();
3343 + $is_elementor_callable = defined('ELEMENTOR_VERSION') && is_callable('Elementor\Plugin::instance');
3344 +
3345 + if ($is_elementor_callable) {
3346 + self::$elementor_instance = Elementor\Plugin::instance();
3347 +
3348 + // TODO: Add popular themes
3349 + switch ($template) {
3350 + case 'hello-elementor':
3351 + require_once(KING_ADDONS_PATH . 'includes/extensions/Header_Footer_Builder/themes/hello-elementor/ELHF_Hello_Elementor.php');
3352 + break;
3353 + default:
3354 + add_action('init', [$this, 'setupSettingsPage']);
3355 + add_filter('king_addons_el_hf_settings_tabs', [$this, 'setupUnsupportedTheme']);
3356 + add_action('init', [$this, 'setupFallbackSupport']);
3357 + break;
3358 + }
3359 + }
3360 + }
3361 +
3362 + public function setupUnsupportedTheme($settings_tabs = [])
3363 + {
3364 + if (!current_theme_supports('king-addons-elementor-header-footer')) {
3365 + $settings_tabs['king_addons_el_hf_settings'] = [
3366 + 'name' => esc_html__('Display Settings', 'king-addons'),
3367 + 'url' => admin_url('admin.php?page=king-addons-el-hf&tab=settings'),
3368 + ];
3369 + }
3370 + return $settings_tabs;
3371 + }
3372 +
3373 + public function setupFallbackSupport()
3374 + {
3375 + if (!current_theme_supports('king-addons-elementor-header-footer')) {
3376 + // Default to Method 3 (Universal) for best compatibility
3377 + $compatibility_option = get_option('king_addons_el_hf_compatibility_option', '3');
3378 +
3379 + if ('1' === $compatibility_option) {
3380 + if (!class_exists('ELHF_Default_Method_1')) {
3381 + require_once(KING_ADDONS_PATH . 'includes/extensions/Header_Footer_Builder/themes/default/ELHF_Default_Method_1.php');
3382 + }
3383 + } elseif ('2' === $compatibility_option) {
3384 + if (!class_exists('ELHF_Default_Method_2')) {
3385 + require_once(KING_ADDONS_PATH . 'includes/extensions/Header_Footer_Builder/themes/default/ELHF_Default_Method_2.php');
3386 + }
3387 + } else {
3388 + // Method 3: Universal (combines all approaches for maximum compatibility)
3389 + if (!class_exists('ELHF_Default_Method_3')) {
3390 + require_once(KING_ADDONS_PATH . 'includes/extensions/Header_Footer_Builder/themes/default/ELHF_Default_Method_3.php');
3391 + }
3392 + }
3393 + }
3394 + }
3395 +
3396 + function setupSettingsPage()
3397 + {
3398 + require_once(KING_ADDONS_PATH . 'includes/extensions/Header_Footer_Builder/ELHF_Settings_Page.php');
3399 + }
3400 +
3401 + public static function renderHeader()
3402 + {
3403 + /** @noinspection SpellCheckingInspection */
3404 + echo '<header id="masthead" class="king-addons-el-hf-header" itemscope="itemscope" itemtype="https://schema.org/WPHeader">';
3405 + ?><p class="main-title" style="display: none;" itemprop="headline"><a
3406 + href="<?php echo esc_url(get_bloginfo('url')); ?>"
3407 + title="<?php echo esc_attr(get_bloginfo('name', 'display')); ?>"
3408 + rel="home"><?php echo esc_html(get_bloginfo('name')); ?></a></p><?php
3409 + self::getHeaderContent();
3410 + echo '</header>';
3411 + }
3412 +
3413 + public static function renderFooter()
3414 + {
3415 + /** @noinspection SpellCheckingInspection */
3416 + echo '<footer id="colophon" class="king-addons-el-hf-footer" itemscope="itemscope" itemtype="https://schema.org/WPFooter" role="contentinfo">';
3417 + self::getFooterContent();
3418 + echo '</footer>';
3419 + }
3420 +
3421 + public static function getHeaderContent()
3422 + {
3423 + $header_id = self::getHeaderID();
3424 + if ($header_id) {
3425 + // Ensure Elementor-generated CSS is included on non-Elementor pages.
3426 + $with_css = true;
3427 + echo self::$elementor_instance->frontend->get_builder_content_for_display($header_id, $with_css); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
3428 + }
3429 + }
3430 +
3431 + public static function getFooterContent()
3432 + {
3433 + $footer_id = self::getFooterID();
3434 + if ($footer_id) {
3435 + echo '<div style="width: 100%;">';
3436 + // Ensure Elementor-generated CSS is included on non-Elementor pages.
3437 + $with_css = true;
3438 + echo self::$elementor_instance->frontend->get_builder_content_for_display($footer_id, $with_css); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
3439 + echo '</div>';
3440 + }
3441 + }
3442 +
3443 + public static function getHeaderID()
3444 + {
3445 + $header_id = self::getSettings('king_addons_el_hf_type_header');
3446 +
3447 + if ('' === $header_id) {
3448 + $header_id = false;
3449 + }
3450 +
3451 + return apply_filters('king_addons_el_hf_get_header_id', $header_id);
3452 + }
3453 +
3454 + public static function isHeaderEnabled()
3455 + {
3456 + $header_id = self::getSettings('king_addons_el_hf_type_header');
3457 + $status = false;
3458 +
3459 + if ('' !== $header_id) {
3460 + $status = true;
3461 + }
3462 +
3463 + return apply_filters('king_addons_el_hf_header_enabled', $status);
3464 + }
3465 +
3466 + public static function isFooterEnabled()
3467 + {
3468 + $footer_id = self::getSettings('king_addons_el_hf_type_footer');
3469 + $status = false;
3470 +
3471 + if ('' !== $footer_id) {
3472 + $status = true;
3473 + }
3474 +
3475 + return apply_filters('king_addons_el_hf_footer_enabled', $status);
3476 + }
3477 +
3478 + public static function getFooterID()
3479 + {
3480 + $footer_id = self::getSettings('king_addons_el_hf_type_footer');
3481 +
3482 + if ('' === $footer_id) {
3483 + $footer_id = false;
3484 + }
3485 +
3486 + return apply_filters('king_addons_el_hf_get_footer_id', $footer_id);
3487 + }
3488 +
3489 +
3490 + public static function getSettings($setting = '')
3491 + {
3492 + if ('king_addons_el_hf_type_header' == $setting || 'king_addons_el_hf_type_footer' == $setting) {
3493 + $templates = self::getTemplateID($setting);
3494 + $template = !is_array($templates) ? $templates : $templates[0];
3495 + return apply_filters("king_addons_el_hf_get_settings_$setting", $template);
3496 + }
3497 +
3498 + return null;
3499 + }
3500 +
3501 + public static function getTemplateID($type)
3502 + {
3503 + $option = [
3504 + 'location' => 'king_addons_el_hf_target_include_locations',
3505 + 'exclusion' => 'king_addons_el_hf_target_exclude_locations',
3506 + 'users' => 'king_addons_el_hf_target_user_roles',
3507 + ];
3508 +
3509 + $templates = self::getPostsByConditions('king-addons-el-hf', $option);
3510 +
3511 + // Prime meta cache to avoid N+1 queries when calling get_post_meta in loops below.
3512 + // getPostsByConditions() may already have populated template IDs; caching is safe and cheap.
3513 + if (!empty($templates)) {
3514 + $template_ids = array_map(static function ($template) {
3515 + return isset($template['id']) ? absint($template['id']) : 0;
3516 + }, $templates);
3517 + $template_ids = array_values(array_filter($template_ids));
3518 + if (!empty($template_ids)) {
3519 + update_meta_cache('post', $template_ids);
3520 + }
3521 + }
3522 +
3523 + foreach ($templates as $template) {
3524 + if (get_post_meta(absint($template['id']), 'king_addons_el_hf_template_type', true) === $type) {
3525 + // Polylang check - https://polylang.pro/doc/function-reference/
3526 + if (function_exists('pll_current_language')) {
3527 + if (pll_current_language('slug') == pll_get_post_language($template['id'], 'slug')) {
3528 + return $template['id'];
3529 + }
3530 + } else {
3531 + return $template['id'];
3532 + }
3533 + }
3534 + }
3535 +
3536 + return '';
3537 + }
3538 +
3539 + public static function getPostsByConditions($post_type, $option)
3540 + {
3541 + global $wpdb;
3542 + global $post;
3543 +
3544 + // Security fix: Validate and sanitize post_type
3545 + // Ensure $post is valid before accessing its properties
3546 + if ($post_type) {
3547 + $post_type = sanitize_key($post_type);
3548 + } elseif ($post instanceof \WP_Post && !empty($post->post_type)) {
3549 + $post_type = sanitize_key($post->post_type);
3550 + } else {
3551 + return [];
3552 + }
3553 +
3554 + if (empty($post_type)) {
3555 + return [];
3556 + }
3557 +
3558 + if (is_array(self::$current_page_data) && isset(self::$current_page_data[$post_type])) {
3559 + return apply_filters('king_addons_el_hf_get_display_posts_by_conditions', self::$current_page_data[$post_type], $post_type);
3560 + }
3561 +
3562 + $current_page_type = self::getCurrentPageType();
3563 +
3564 + self::$current_page_data[$post_type] = array();
3565 +
3566 + $option['current_post_id'] = self::$current_page_data['ID'];
3567 + $meta_header = self::getMetaOptionPost($post_type, $option);
3568 +
3569 + if (false === $meta_header) {
3570 + $current_post_type = sanitize_key(get_post_type());
3571 + $current_post_id = false;
3572 + $q_obj = get_queried_object();
3573 +
3574 + $current_id = absint(get_the_id());
3575 +
3576 + // Check if WPML is active. Find WPML Object ID for current page.
3577 + /** @noinspection SpellCheckingInspection */
3578 + if (defined('ICL_SITEPRESS_VERSION')) {
3579 + $default_lang = apply_filters('wpml_default_language', '');
3580 + $current_lang = apply_filters('wpml_current_language', '');
3581 +
3582 + if ($default_lang !== $current_lang) {
3583 + $current_post_type = get_post_type($current_id);
3584 + $current_id = apply_filters('wpml_object_id', $current_id, $current_post_type, true, $default_lang);
3585 + }
3586 + }
3587 +
3588 + // Security fix: Sanitize location parameter
3589 + $location = isset($option['location']) ? sanitize_key($option['location']) : '';
3590 + if (empty($location)) {
3591 + return [];
3592 + }
3593 +
3594 + // Security fix: Use prepared statement to prevent SQL injection
3595 + $query = $wpdb->prepare(
3596 + "SELECT p.ID, pm.meta_value FROM {$wpdb->postmeta} as pm
3597 + INNER JOIN {$wpdb->posts} as p ON pm.post_id = p.ID
3598 + WHERE pm.meta_key = %s
3599 + AND p.post_type = %s
3600 + AND p.post_status = 'publish'",
3601 + $location,
3602 + $post_type
3603 + );
3604 +
3605 + $orderby = ' ORDER BY p.post_date DESC';
3606 +
3607 + // Security fix: Build meta_args using safe placeholders and prepared statements
3608 + $meta_conditions = ["pm.meta_value LIKE %s"];
3609 + $meta_values = ['%"basic-global"%'];
3610 +
3611 + switch ($current_page_type) {
3612 + case 'is_404':
3613 + $meta_conditions[] = "pm.meta_value LIKE %s";
3614 + $meta_values[] = '%"special-404"%';
3615 + break;
3616 + case 'is_search':
3617 + $meta_conditions[] = "pm.meta_value LIKE %s";
3618 + $meta_values[] = '%"special-search"%';
3619 + break;
3620 + case 'is_archive':
3621 + case 'is_tax':
3622 + case 'is_date':
3623 + case 'is_author':
3624 + $meta_conditions[] = "pm.meta_value LIKE %s";
3625 + $meta_values[] = '%"basic-archives"%';
3626 + $meta_conditions[] = "pm.meta_value LIKE %s";
3627 + $meta_values[] = '%"' . sanitize_key($current_post_type) . '|all|archive"%';
3628 +
3629 + if ('is_tax' == $current_page_type && (is_category() || is_tag() || is_tax())) {
3630 + if (is_object($q_obj) && isset($q_obj->taxonomy) && isset($q_obj->term_id)) {
3631 + $meta_conditions[] = "pm.meta_value LIKE %s";
3632 + $meta_values[] = '%"' . sanitize_key($current_post_type) . '|all|taxarchive|' . sanitize_key($q_obj->taxonomy) . '"%';
3633 + $meta_conditions[] = "pm.meta_value LIKE %s";
3634 + $meta_values[] = '%"tax-' . absint($q_obj->term_id) . '"%';
3635 + }
3636 + } elseif ('is_date' == $current_page_type) {
3637 + $meta_conditions[] = "pm.meta_value LIKE %s";
3638 + $meta_values[] = '%"special-date"%';
3639 + } elseif ('is_author' == $current_page_type) {
3640 + $meta_conditions[] = "pm.meta_value LIKE %s";
3641 + $meta_values[] = '%"special-author"%';
3642 + }
3643 + break;
3644 + case 'is_home':
3645 + $meta_conditions[] = "pm.meta_value LIKE %s";
3646 + $meta_values[] = '%"special-blog"%';
3647 + break;
3648 + case 'is_front_page':
3649 + $current_post_id = $current_id;
3650 + $meta_conditions[] = "pm.meta_value LIKE %s";
3651 + $meta_values[] = '%"special-front"%';
3652 + $meta_conditions[] = "pm.meta_value LIKE %s";
3653 + $meta_values[] = '%"' . sanitize_key($current_post_type) . '|all"%';
3654 + $meta_conditions[] = "pm.meta_value LIKE %s";
3655 + $meta_values[] = '%"post-' . absint($current_id) . '"%';
3656 + break;
3657 + case 'is_singular':
3658 + $current_post_id = $current_id;
3659 + $meta_conditions[] = "pm.meta_value LIKE %s";
3660 + $meta_values[] = '%"basic-singulars"%';
3661 + $meta_conditions[] = "pm.meta_value LIKE %s";
3662 + $meta_values[] = '%"' . sanitize_key($current_post_type) . '|all"%';
3663 + $meta_conditions[] = "pm.meta_value LIKE %s";
3664 + $meta_values[] = '%"post-' . absint($current_id) . '"%';
3665 +
3666 + if (is_object($q_obj) && isset($q_obj->post_type) && isset($q_obj->ID)) {
3667 + $taxonomies = get_object_taxonomies($q_obj->post_type);
3668 + $terms = wp_get_post_terms($q_obj->ID, $taxonomies);
3669 + foreach ($terms as $term) {
3670 + if (isset($term->term_id) && isset($term->taxonomy)) {
3671 + $meta_conditions[] = "pm.meta_value LIKE %s";
3672 + $meta_values[] = '%"tax-' . absint($term->term_id) . '-single-' . sanitize_key($term->taxonomy) . '"%';
3673 + }
3674 + }
3675 + }
3676 + break;
3677 + case 'is_woo_shop_page':
3678 + if (function_exists('is_shop')) {
3679 + $meta_conditions[] = "pm.meta_value LIKE %s";
3680 + $meta_values[] = '%"special-woocommerce-shop"%';
3681 + }
3682 + break;
3683 + case '':
3684 + $current_post_id = $current_id;
3685 + break;
3686 + }
3687 +
3688 + // Build the final meta_args string using prepare
3689 + $meta_args = '(' . implode(' OR ', $meta_conditions) . ')';
3690 +
3691 + // Security fix: Use prepared statement for the complete query
3692 + $full_query = $wpdb->prepare(
3693 + $query . ' AND ' . $meta_args . $orderby,
3694 + ...$meta_values
3695 + );
3696 +
3697 + $posts = $wpdb->get_results($full_query);
3698 +
3699 + foreach ($posts as $local_post) {
3700 + $unserialized_location = maybe_unserialize($local_post->meta_value);
3701 + if ($unserialized_location !== false) {
3702 + self::$current_page_data[$post_type][$local_post->ID] = array(
3703 + 'id' => $local_post->ID,
3704 + 'location' => $unserialized_location,
3705 + );
3706 + }
3707 + }
3708 +
3709 + // Prime meta cache for all candidate templates to avoid repeated get_post_meta queries
3710 + // in removeExclusionRulePosts/removeUserRulePosts and getTemplateID.
3711 + if (!empty(self::$current_page_data[$post_type])) {
3712 + $candidate_ids = array_map('absint', array_keys(self::$current_page_data[$post_type]));
3713 + $candidate_ids = array_values(array_filter($candidate_ids));
3714 + if (!empty($candidate_ids)) {
3715 + update_meta_cache('post', $candidate_ids);
3716 + }
3717 + }
3718 +
3719 + $option['current_post_id'] = $current_post_id;
3720 +
3721 + self::removeExclusionRulePosts($post_type, $option);
3722 + self::removeUserRulePosts($post_type, $option);
3723 + }
3724 +
3725 + return apply_filters('king_addons_el_hf_get_display_posts_by_conditions', self::$current_page_data[$post_type], $post_type);
3726 + }
3727 +
3728 + public static function getCurrentPageType(): ?string
3729 + {
3730 + if (null === self::$current_page_type) {
3731 + $page_type = '';
3732 + $current_id = false;
3733 +
3734 + if (is_404()) {
3735 + $page_type = 'is_404';
3736 + } elseif (is_search()) {
3737 + $page_type = 'is_search';
3738 + } elseif (is_archive()) {
3739 + $page_type = 'is_archive';
3740 + if (is_category() || is_tag() || is_tax()) {
3741 + $page_type = 'is_tax';
3742 + } elseif (is_date()) {
3743 + $page_type = 'is_date';
3744 + } elseif (is_author()) {
3745 + $page_type = 'is_author';
3746 + } elseif (function_exists('is_shop')) {
3747 + /** @noinspection PhpUndefinedFunctionInspection */
3748 + if (is_shop()) {
3749 + $page_type = 'is_woo_shop_page';
3750 + }
3751 + }
3752 + } elseif (is_home()) {
3753 + $page_type = 'is_home';
3754 + } elseif (is_front_page()) {
3755 + $page_type = 'is_front_page';
3756 + $current_id = get_the_id();
3757 + } elseif (is_singular()) {
3758 + $page_type = 'is_singular';
3759 + $current_id = get_the_id();
3760 + } else {
3761 + $current_id = get_the_id();
3762 + }
3763 +
3764 + self::$current_page_data['ID'] = $current_id;
3765 + self::$current_page_type = $page_type;
3766 + }
3767 +
3768 + return self::$current_page_type;
3769 + }
3770 +
3771 + public static function getMetaOptionPost($post_type, $option)
3772 + {
3773 + $page_meta = (isset($option['page_meta']) && '' != $option['page_meta']) ? $option['page_meta'] : false;
3774 +
3775 + if (false !== $page_meta) {
3776 + $current_post_id = $option['current_post_id'] ?? false;
3777 + $meta_id = get_post_meta($current_post_id, $option['page_meta'], true);
3778 +
3779 + if (false !== $meta_id && '' != $meta_id) {
3780 + self::$current_page_data[$post_type][$meta_id] = array(
3781 + 'id' => $meta_id,
3782 + 'location' => '',
3783 + );
3784 +
3785 + return self::$current_page_data[$post_type];
3786 + }
3787 + }
3788 +
3789 + return false;
3790 + }
3791 +
3792 + public static function removeExclusionRulePosts($post_type, $option)
3793 + {
3794 + $exclusion = $option['exclusion'] ?? '';
3795 + $current_post_id = $option['current_post_id'] ?? false;
3796 + foreach (self::$current_page_data[$post_type] as $c_post_id => $c_data) {
3797 + $exclusion_rules = get_post_meta($c_post_id, $exclusion, true);
3798 + $is_exclude = self::parseLayoutDisplayCondition($current_post_id, $exclusion_rules);
3799 + if ($is_exclude) {
3800 + unset(self::$current_page_data[$post_type][$c_post_id]);
3801 + }
3802 + }
3803 + }
3804 +
3805 + public static function removeUserRulePosts($post_type, $option)
3806 + {
3807 + $users = $option['users'] ?? '';
3808 +
3809 + foreach (self::$current_page_data[$post_type] as $c_post_id => $c_data) {
3810 + $user_rules = get_post_meta($c_post_id, $users, true);
3811 + $is_user = self::parseUserRoleCondition($user_rules);
3812 +
3813 + if (!$is_user) {
3814 + unset(self::$current_page_data[$post_type][$c_post_id]);
3815 + }
3816 + }
3817 + }
3818 +
3819 + public static function parseLayoutDisplayCondition($post_id, $rules): bool
3820 + {
3821 + $display = false;
3822 +
3823 + /** @noinspection PhpConditionCheckedByNextConditionInspection */
3824 + if (isset($rules['rule']) && is_array($rules['rule']) && !empty($rules['rule'])) {
3825 + foreach ($rules['rule'] as $rule) {
3826 + if (strrpos($rule, 'all') !== false) {
3827 + $rule_case = 'all';
3828 + } else {
3829 + $rule_case = $rule;
3830 + }
3831 +
3832 + switch ($rule_case) {
3833 + case 'basic-global':
3834 + $display = true;
3835 + break;
3836 +
3837 + case 'basic-singulars':
3838 + if (is_singular()) {
3839 + $display = true;
3840 + }
3841 + break;
3842 +
3843 + case 'basic-archives':
3844 + if (is_archive()) {
3845 + $display = true;
3846 + }
3847 + break;
3848 +
3849 + case 'special-404':
3850 + if (is_404()) {
3851 + $display = true;
3852 + }
3853 + break;
3854 +
3855 + case 'special-search':
3856 + if (is_search()) {
3857 + $display = true;
3858 + }
3859 + break;
3860 +
3861 + case 'special-blog':
3862 + if (is_home()) {
3863 + $display = true;
3864 + }
3865 + break;
3866 +
3867 + case 'special-front':
3868 + if (is_front_page()) {
3869 + $display = true;
3870 + }
3871 + break;
3872 +
3873 + case 'special-date':
3874 + if (is_date()) {
3875 + $display = true;
3876 + }
3877 + break;
3878 +
3879 + case 'special-author':
3880 + if (is_author()) {
3881 + $display = true;
3882 + }
3883 + break;
3884 +
3885 + case 'special-woocommerce-shop':
3886 + if (function_exists('is_shop')) {
3887 + if (is_shop()) {
3888 + $display = true;
3889 + }
3890 + }
3891 + break;
3892 +
3893 + case 'all':
3894 + $rule_data = explode('|', $rule);
3895 +
3896 + $post_type = $rule_data[0] ?? false;
3897 + $archive_type = $rule_data[2] ?? false;
3898 + $taxonomy = $rule_data[3] ?? false;
3899 + if (false === $archive_type) {
3900 + $current_post_type = get_post_type($post_id);
3901 + if (false !== $post_id && $current_post_type == $post_type) {
3902 + $display = true;
3903 + }
3904 + } else {
3905 + if (is_archive()) {
3906 + $current_post_type = get_post_type();
3907 + if ($current_post_type == $post_type) {
3908 + if ('archive' == $archive_type) {
3909 + $display = true;
3910 + } elseif ('taxarchive' == $archive_type) {
3911 + $obj = get_queried_object();
3912 + $current_taxonomy = '';
3913 + if ('' !== $obj && null !== $obj) {
3914 + $current_taxonomy = $obj->taxonomy;
3915 + }
3916 +
3917 + if ($current_taxonomy == $taxonomy) {
3918 + $display = true;
3919 + }
3920 + }
3921 + }
3922 + }
3923 + }
3924 + break;
3925 +
3926 + case 'specifics':
3927 + if (isset($rules['specific']) && is_array($rules['specific'])) {
3928 + foreach ($rules['specific'] as $specific_page) {
3929 + $specific_data = explode('-', $specific_page);
3930 + $specific_post_type = $specific_data[0] ?? false;
3931 + $specific_post_id = $specific_data[1] ?? false;
3932 + if ('post' == $specific_post_type) {
3933 + if ($specific_post_id == $post_id) {
3934 + $display = true;
3935 + }
3936 + } elseif (isset($specific_data[2]) && ('single' == $specific_data[2]) && 'tax' == $specific_post_type) {
3937 + if (is_singular()) {
3938 + $term_details = get_term($specific_post_id);
3939 +
3940 + if (isset($term_details->taxonomy)) {
3941 + $has_term = has_term((int)$specific_post_id, $term_details->taxonomy, $post_id);
3942 +
3943 + if ($has_term) {
3944 + $display = true;
3945 + }
3946 + }
3947 + }
3948 + } elseif ('tax' == $specific_post_type) {
3949 + $tax_id = get_queried_object_id();
3950 + if ($specific_post_id == $tax_id) {
3951 + $display = true;
3952 + }
3953 + }
3954 + }
3955 + }
3956 + break;
3957 +
3958 + default:
3959 + break;
3960 + }
3961 +
3962 + if ($display) {
3963 + break;
3964 + }
3965 + }
3966 + }
3967 +
3968 + return $display;
3969 + }
3970 +
3971 + public static function parseUserRoleCondition($rules): bool
3972 + {
3973 + $show_popup = true;
3974 +
3975 + if (is_array($rules) && !empty($rules)) {
3976 + $show_popup = false;
3977 +
3978 + foreach ($rules as $rule) {
3979 + switch ($rule) {
3980 + case '':
3981 + case 'all':
3982 + $show_popup = true;
3983 + break;
3984 +
3985 + case 'logged-in':
3986 + if (is_user_logged_in()) {
3987 + $show_popup = true;
3988 + }
3989 + break;
3990 +
3991 + case 'logged-out':
3992 + if (!is_user_logged_in()) {
3993 + $show_popup = true;
3994 + }
3995 + break;
3996 +
3997 + default:
3998 + if (is_user_logged_in()) {
3999 + $current_user = wp_get_current_user();
4000 +
4001 + if (isset($current_user->roles)
4002 + && is_array($current_user->roles)
4003 + && in_array($rule, $current_user->roles)
4004 + ) {
4005 + $show_popup = true;
4006 + }
4007 + }
4008 + break;
4009 + }
4010 +
4011 + if ($show_popup) {
4012 + break;
4013 + }
4014 + }
4015 + }
4016 +
4017 + return $show_popup;
4018 + }
4019 +
4020 + public static function checkUserCanEdit()
4021 + {
4022 + if (is_singular('king-addons-el-hf') && !current_user_can('edit_posts')) {
4023 + wp_redirect(site_url(), 301);
4024 + die;
4025 + }
4026 + }
4027 +
4028 + public static function loadElementorCanvasTemplate($single_template)
4029 + {
4030 + global $post;
4031 +
4032 + // Safety check: ensure $post is a valid WP_Post object before accessing properties
4033 + if (!$post instanceof \WP_Post) {
4034 + return $single_template;
4035 + }
4036 +
4037 + if ('king-addons-el-hf' === $post->post_type) {
4038 + if (defined('ELEMENTOR_VERSION')) {
4039 + $elementor_2_0_canvas = ELEMENTOR_PATH . '/modules/page-templates/templates/canvas.php';
4040 +
4041 + if (file_exists($elementor_2_0_canvas)) {
4042 + return $elementor_2_0_canvas;
4043 + } else {
4044 + return ELEMENTOR_PATH . '/includes/page-templates/canvas.php';
4045 + }
4046 + }
4047 + }
4048 +
4049 + return $single_template;
4050 + }
4051 +
4052 + public function forceElementorCanvasTemplate($template)
4053 + {
4054 + if (!defined('ELEMENTOR_VERSION')) {
4055 + return $template;
4056 + }
4057 +
4058 + $post_id = 0;
4059 +
4060 + if (is_singular('king-addons-el-hf')) {
4061 + $post_id = (int) get_queried_object_id();
4062 + } elseif (isset($_GET['elementor-preview'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
4063 + $post_id = (int) $_GET['elementor-preview'];
4064 + }
4065 +
4066 + if ($post_id && 'king-addons-el-hf' === get_post_type($post_id)) {
4067 + $elementor_2_0_canvas = ELEMENTOR_PATH . '/modules/page-templates/templates/canvas.php';
4068 + if (file_exists($elementor_2_0_canvas)) {
4069 + return $elementor_2_0_canvas;
4070 + }
4071 + return ELEMENTOR_PATH . '/includes/page-templates/canvas.php';
4072 + }
4073 +
4074 + return $template;
4075 + }
4076 +
4077 + public function forcePreviewQuery($query): void
4078 + {
4079 + if (is_admin() || !$query->is_main_query()) {
4080 + return;
4081 + }
4082 +
4083 + if (!isset($_GET['elementor-preview'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
4084 + return;
4085 + }
4086 +
4087 + $preview_id = (int) $_GET['elementor-preview']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
4088 + if (!$preview_id || 'king-addons-el-hf' !== get_post_type($preview_id)) {
4089 + return;
4090 + }
4091 +
4092 + $query->set('p', $preview_id);
4093 + $query->set('post_type', 'king-addons-el-hf');
4094 + $query->set('post_status', ['publish', 'draft', 'pending', 'private']);
4095 + }
4096 +
4097 + public static function enqueueScripts(): void
4098 + {
4099 + $screen = get_current_screen();
4100 + if ($screen->id === 'edit-king-addons-el-hf') {
4101 + // todo - styles
4102 +// wp_enqueue_style('king-addons-el-hf-style', KING_ADDONS_URL . 'includes/extensions/Header_Footer_Builder/header-footer-builder.css', '', KING_ADDONS_VERSION);
4103 + wp_enqueue_style('king-addons-el-hf-style', KING_ADDONS_URL . 'includes/extensions/Header_Footer_Builder/admin.css', '', KING_ADDONS_VERSION);
4104 + }
4105 + }
4106 +
4107 + public static function columnHeadings($columns)
4108 + {
4109 + unset($columns['date']);
4110 + $columns['king_addons_el_hf_edit_template'] = esc_html__('Edit Template', 'king-addons');
4111 + $columns['king_addons_el_hf_type_of_template'] = esc_html__('Type of Template', 'king-addons');
4112 + $columns['king_addons_el_hf_display_rules'] = esc_html__('Display Rules', 'king-addons');
4113 + $columns['date'] = esc_html__('Date', 'king-addons');
4114 + return $columns;
4115 + }
4116 +
4117 + public static function columnContent($column, $post_id)
4118 + {
4119 + // Edit Template
4120 + if ('king_addons_el_hf_edit_template' === $column) {
4121 + echo '<a class="king-addons-el-hf-edit-template-btn" href="';
4122 + echo './post.php?post=' . esc_attr($post_id) . '&action=edit';
4123 + echo '">' . esc_html__('Edit Template', 'king-addons') . '</a>';
4124 + }
4125 +
4126 + // Display Rules
4127 + if ('king_addons_el_hf_display_rules' === $column) {
4128 +
4129 + $locations = get_post_meta($post_id, 'king_addons_el_hf_target_include_locations', true);
4130 + if (!empty($locations)) {
4131 + echo '<div style="margin-bottom: 5px;">';
4132 + echo '<strong>';
4133 + echo esc_html__('Display: ', 'king-addons');
4134 + echo '</strong>';
4135 + self::columnDisplayLocation($locations);
4136 + echo '</div>';
4137 + }
4138 +
4139 + $locations = get_post_meta($post_id, 'king_addons_el_hf_target_exclude_locations', true);
4140 + if (!empty($locations)) {
4141 + echo '<div style="margin-bottom: 5px;">';
4142 + echo '<strong>';
4143 + echo esc_html__('Exclusion: ', 'king-addons');
4144 + echo '</strong>';
4145 + self::columnDisplayLocation($locations);
4146 + echo '</div>';
4147 + }
4148 +
4149 + $users = get_post_meta($post_id, 'king_addons_el_hf_target_user_roles', true);
4150 + if (isset($users) && is_array($users)) {
4151 + if (!empty($users[0])) {
4152 + $user_label = [];
4153 + foreach ($users as $user) {
4154 + $user_label[] = self::get_user_by_key($user);
4155 + }
4156 + echo '<div>';
4157 + echo '<strong>Users: </strong>';
4158 + echo esc_html(join(', ', $user_label));
4159 + echo '</div>';
4160 + }
4161 + }
4162 +
4163 + }
4164 +
4165 + // Type of Template
4166 + if ('king_addons_el_hf_type_of_template' === $column) {
4167 + $template_type = get_post_meta($post_id, 'king_addons_el_hf_template_type', true);
4168 + if (!empty($template_type)) {
4169 + echo '<div style="margin-bottom: 5px;">';
4170 + echo '<strong>';
4171 + switch ($template_type) {
4172 + case 'king_addons_el_hf_type_header':
4173 + echo esc_html__('Header', 'king-addons');
4174 + break;
4175 + case 'king_addons_el_hf_type_footer':
4176 + echo esc_html__('Footer', 'king-addons');
4177 + break;
4178 + default:
4179 + echo esc_html__('Not selected', 'king-addons');
4180 + break;
4181 + }
4182 + echo '</strong>';
4183 + echo '</div>';
4184 + }
4185 + }
4186 + }
4187 +
4188 + public static function get_user_by_key($key)
4189 + {
4190 + if (!isset(self::$user_selection) || empty(self::$user_selection)) {
4191 + self::$user_selection = self::get_user_selections();
4192 + }
4193 + $user_selection = self::$user_selection;
4194 +
4195 + if (isset($user_selection['basic']['value'][$key])) {
4196 + return $user_selection['basic']['value'][$key];
4197 + } elseif ($user_selection['advanced']['value'][$key]) {
4198 + return $user_selection['advanced']['value'][$key];
4199 + }
4200 + return $key;
4201 + }
4202 +
4203 + public static function columnDisplayLocation($locations)
4204 + {
4205 + $location_label = [];
4206 + /** @noinspection PhpConditionAlreadyCheckedInspection */
4207 + if (is_array($locations) && is_array($locations['rule']) && isset($locations['rule'])) {
4208 + /** @noinspection PhpArraySearchInBooleanContextInspection */
4209 + $index = array_search('specifics', $locations['rule']);
4210 + /** @noinspection PhpConditionCheckedByNextConditionInspection */
4211 + if (false !== $index && !empty($index)) {
4212 + unset($locations['rule'][$index]);
4213 + }
4214 + }
4215 +
4216 + if (isset($locations['rule']) && is_array($locations['rule'])) {
4217 + foreach ($locations['rule'] as $location) {
4218 + $location_label[] = self::getLocation($location);
4219 + }
4220 + }
4221 +
4222 + if (isset($locations['specific']) && is_array($locations['specific'])) {
4223 + foreach ($locations['specific'] as $location) {
4224 + $location_label[] = self::getLocation($location);
4225 + }
4226 + }
4227 +
4228 + echo esc_html(join(', ', $location_label));
4229 + }
4230 +
4231 + public static function getLocation($key)
4232 + {
4233 + if (!isset(self::$location_selection) || empty(self::$location_selection)) {
4234 + self::$location_selection = self::getLocationSelections();
4235 + }
4236 +
4237 + $location_selection = self::$location_selection;
4238 +
4239 + foreach ($location_selection as $location_grp) {
4240 + if (isset($location_grp['value'][$key])) {
4241 + return $location_grp['value'][$key];
4242 + }
4243 + }
4244 +
4245 + if (strpos($key, 'post-') !== false) {
4246 + $post_id = (int)str_replace('post-', '', $key);
4247 + return get_the_title($post_id);
4248 + }
4249 +
4250 + if (strpos($key, 'tax-') !== false) {
4251 + $tax_id = (int)str_replace('tax-', '', $key);
4252 + $term = get_term($tax_id);
4253 +
4254 + if (!is_wp_error($term)) {
4255 + $term_taxonomy = ucfirst(str_replace('_', ' ', $term->taxonomy));
4256 + return $term->name . ' - ' . $term_taxonomy;
4257 + } else {
4258 + return '';
4259 + }
4260 + }
4261 +
4262 + return $key;
4263 + }
4264 +
4265 + public static function getLocationSelections()
4266 + {
4267 + $args = array(
4268 + 'public' => true,
4269 + '_builtin' => true,
4270 + );
4271 +
4272 + $post_types = get_post_types($args, 'objects');
4273 + unset($post_types['attachment']);
4274 +
4275 + $args['_builtin'] = false;
4276 + $custom_post_type = get_post_types($args, 'objects');
4277 +
4278 + $post_types = apply_filters('king_addons_el_hf_location_rule_post_types', array_merge($post_types, $custom_post_type));
4279 +
4280 + if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
4281 + $special_pages = array(
4282 + 'special-404-none' => esc_html__('404 Page (Available in PRO)', 'king-addons'),
4283 + 'special-search' => esc_html__('Search Page', 'king-addons'),
4284 + 'special-blog-none' => esc_html__('Blog / Posts Page (Available in PRO)', 'king-addons'),
4285 + 'special-front' => esc_html__('Front Page', 'king-addons'),
4286 + 'special-date' => esc_html__('Date Archive', 'king-addons'),
4287 + 'special-author' => esc_html__('Author Archive', 'king-addons'),
4288 + );
4289 + } else {
4290 + $special_pages = array(
4291 + 'special-404' => esc_html__('404 Page', 'king-addons'),
4292 + 'special-search' => esc_html__('Search Page', 'king-addons'),
4293 + 'special-blog' => esc_html__('Blog / Posts Page', 'king-addons'),
4294 + 'special-front' => esc_html__('Front Page', 'king-addons'),
4295 + 'special-date' => esc_html__('Date Archive', 'king-addons'),
4296 + 'special-author' => esc_html__('Author Archive', 'king-addons'),
4297 + );
4298 + }
4299 +
4300 + if (class_exists('WooCommerce')) {
4301 + if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
4302 + $special_pages['special-woocommerce-shop-none'] = esc_html__('WooCommerce Shop Page (Available in PRO)', 'king-addons');
4303 + } else {
4304 + $special_pages['special-woocommerce-shop'] = esc_html__('WooCommerce Shop Page', 'king-addons');
4305 + }
4306 + }
4307 +
4308 + $selection_options = array(
4309 + 'basic' => array(
4310 + 'label' => esc_html__('Basic', 'king-addons'),
4311 + 'value' => array(
4312 + 'basic-global' => esc_html__('Entire Website', 'king-addons'),
4313 + 'basic-singulars' => esc_html__('All Singulars', 'king-addons'),
4314 + 'basic-archives' => esc_html__('All Archives', 'king-addons'),
4315 + ),
4316 + ),
4317 +
4318 + 'special-pages' => array(
4319 + 'label' => esc_html__('Special Pages', 'king-addons'),
4320 + 'value' => $special_pages,
4321 + ),
4322 + );
4323 +
4324 + if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
4325 + $selection_options['specific-target'] = array(
4326 + 'label' => esc_html__('Specific Target', 'king-addons'),
4327 + 'value' => array(
4328 + 'specifics-none' => esc_html__('Specific Pages / Posts / Taxonomies, etc. (Available in PRO)', 'king-addons'),
4329 + ),
4330 + );
4331 + } else {
4332 + $selection_options['specific-target'] = array(
4333 + 'label' => esc_html__('Specific Target', 'king-addons'),
4334 + 'value' => array(
4335 + 'specifics' => esc_html__('Specific Pages / Posts / Taxonomies, etc.', 'king-addons'),
4336 + ),
4337 + );
4338 + }
4339 +
4340 + $args = array(
4341 + 'public' => true,
4342 + );
4343 +
4344 + $taxonomies = get_taxonomies($args, 'objects');
4345 +
4346 + if (!empty($taxonomies)) {
4347 + foreach ($taxonomies as $taxonomy) {
4348 +
4349 + if ('post_format' == $taxonomy->name) {
4350 + continue;
4351 + }
4352 +
4353 + foreach ($post_types as $post_type) {
4354 + $post_opt = self::getPostTargetRuleOptions($post_type, $taxonomy);
4355 +
4356 + if (isset($selection_options[$post_opt['post_key']])) {
4357 + if (!empty($post_opt['value']) && is_array($post_opt['value'])) {
4358 + foreach ($post_opt['value'] as $key => $value) {
4359 + if (!in_array($value, $selection_options[$post_opt['post_key']]['value'])) {
4360 + $selection_options[$post_opt['post_key']]['value'][$key] = $value;
4361 + }
4362 + }
4363 + }
4364 + } else {
4365 + $selection_options[$post_opt['post_key']] = array(
4366 + 'label' => $post_opt['label'],
4367 + 'value' => $post_opt['value'],
4368 + );
4369 + }
4370 + }
4371 + }
4372 + }
4373 +
4374 + return apply_filters('king_addons_el_hf_display_on_list', $selection_options);
4375 + }
4376 +
4377 + public static function getPostTargetRuleOptions($post_type, $taxonomy): array
4378 + {
4379 + $post_key = str_replace(' ', '-', strtolower($post_type->label));
4380 + $post_label = ucwords($post_type->label);
4381 + $post_name = $post_type->name;
4382 + $post_option = array();
4383 +
4384 + /* translators: %s is post label */
4385 + $all_posts = sprintf(esc_html__('All %s', 'king-addons'), $post_label);
4386 + $post_option[$post_name . '|all'] = $all_posts;
4387 +
4388 + if ('pages' != $post_key) {
4389 + /* translators: %s is post label */
4390 + $all_archive = sprintf(esc_html__('All %s Archive', 'king-addons'), $post_label);
4391 + $post_option[$post_name . '|all|archive'] = $all_archive;
4392 + }
4393 +
4394 + if (in_array($post_type->name, $taxonomy->object_type)) {
4395 + $tax_label = ucwords($taxonomy->label);
4396 + $tax_name = $taxonomy->name;
4397 +
4398 + /* translators: %s is taxonomy label */
4399 + $tax_archive = sprintf(esc_html__('All %s Archive', 'king-addons'), $tax_label);
4400 +
4401 + $post_option[$post_name . '|all|taxarchive|' . $tax_name] = $tax_archive;
4402 + }
4403 +
4404 + $post_output['post_key'] = $post_key;
4405 + $post_output['label'] = $post_label;
4406 + $post_output['value'] = $post_option;
4407 +
4408 + return $post_output;
4409 + }
4410 +
4411 + public static function getFormatRuleValue($save_data, $key): array
4412 + {
4413 + $meta_value = array();
4414 +
4415 + if (isset($save_data[$key]['rule'])) {
4416 + $save_data[$key]['rule'] = array_unique($save_data[$key]['rule']);
4417 + if (isset($save_data[$key]['specific'])) {
4418 + $save_data[$key]['specific'] = array_unique($save_data[$key]['specific']);
4419 + }
4420 +
4421 + $index = array_search('', $save_data[$key]['rule']);
4422 + if (false !== $index) {
4423 + unset($save_data[$key]['rule'][$index]);
4424 + }
4425 + $index = array_search('specifics', $save_data[$key]['rule']);
4426 + if (false !== $index) {
4427 + unset($save_data[$key]['rule'][$index]);
4428 +
4429 + if (isset($save_data[$key]['specific']) && is_array($save_data[$key]['specific'])) {
4430 + $save_data[$key]['rule'][] = 'specifics';
4431 + }
4432 + }
4433 +
4434 + foreach ($save_data[$key] as $meta_key => $value) {
4435 + if (!empty($value)) {
4436 + $meta_value[$meta_key] = array_map('esc_attr', $value);
4437 + }
4438 + }
4439 + if (!isset($meta_value['rule']) || !in_array('specifics', $meta_value['rule'])) {
4440 + $meta_value['specific'] = array();
4441 + }
4442 +
4443 + if (empty($meta_value['rule'])) {
4444 + $meta_value = array();
4445 + }
4446 + }
4447 +
4448 + return $meta_value;
4449 + }
4450 +}