PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.1
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.1
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
← All changes | templates/settings-page.php +80 -78 2.3.42.4.1 View file →
@@ -96,9 +96,9 @@
96 96 $paths = '<circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
97 97 . '<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>';
98 98 break;
99 99 }
100 - echo $open . $paths . $close;
100 + echo $open . $paths . $close; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- inline SVG icon markup assembled from literal path data above.
101 101 }
102 102 }
103 103
104 104 /**
@@ -120,18 +120,18 @@
120 120 $placeholder = isset($field_config['placeholder']) ? esc_attr($field_config['placeholder']) : '';
121 121 $required = !empty($field_config['required']) ? 'required' : '';
122 122 $aria_describedby = !empty($description_text) ? 'aria-describedby="' . $field_id . '-description"' : '';
123 123
124 - echo '<div class=" ' . $col_span_class . '">'; // Added 'form-group' class for JS show/hide functionality
124 + echo '<div class=" ' . esc_html($col_span_class) . '">'; // Added 'form-group' class for JS show/hide functionality
125 125
126 126 // Special layout for checkboxes with descriptions (e.g., Invoice Numbering type)
127 127 if ($type === 'checkbox' && !empty($description_text) && ($option_key === 'easy_invoice_invoice_numbering')) {
128 128 echo '<div class="flex items-start space-x-3 p-4 bg-gray-50 rounded-lg border border-gray-200">';
129 129 echo ' <div class="flex items-center h-5 mt-0.5">';
130 - echo ' <input type="checkbox" name="' . $field_name . '" id="' . $field_id . '" value="yes" ' . checked($value, 'yes', false) . ' class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" ' . $required . '>';
130 + echo ' <input type="checkbox" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="yes" ' . checked($value, 'yes', false) . ' class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" ' . esc_html($required) . '>';
131 131 echo ' </div>';
132 132 echo ' <div class="flex-1">';
133 - echo ' <label for="' . $field_id . '" class="block text-sm font-medium text-gray-700 mb-1">' . $label . '</label>';
133 + echo ' <label for="' . $field_id . '" class="block text-sm font-medium text-gray-700 mb-1">' . esc_html($label) . '</label>';
134 134 echo ' <p id="' . $field_id . '-description" class="text-sm text-gray-400 leading-relaxed">' . wp_kses($description_text, array(
135 135 'a' => array(
136 136 'href' => array(),
137 137 'target' => array(),
@@ -142,9 +142,9 @@
142 142 echo '</div>';
143 143 } else {
144 144 // Standard label for other types, or checkboxes without the special description structure
145 145 if ($type !== 'checkbox') {
146 - echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700 mb-2">' . $label . '</label>';
146 + echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700 mb-2">' . esc_html($label) . '</label>';
147 147 }
148 148
149 149 $input_class = 'mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm';
150 150 $select_class = 'mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md';
@@ -153,21 +153,21 @@
153 153 case 'text':
154 154 case 'email':
155 155 case 'url':
156 156 case 'tel':
157 - echo '<input type="' . esc_attr($type) . '" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . $input_class . '" placeholder="' . $placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
157 + echo '<input type="' . esc_attr($type) . '" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . esc_html($input_class) . '" placeholder="' . esc_html($placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
158 158 break;
159 159 case 'number':
160 160 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
161 161 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
162 162 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
163 - echo '<input type="number" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '"' . $min . $max . $step . ' class="' . $input_class . '" placeholder="' . $placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
163 + echo '<input type="number" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($value) . '"' . $min . $max . $step . ' class="' . esc_html($input_class) . '" placeholder="' . esc_html($placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
164 164 break;
165 165 case 'textarea':
166 - echo '<textarea id="' . $field_id . '" name="' . $field_name . '" rows="3" class="' . $input_class . '" placeholder="' . $placeholder . '" ' . $required . ' ' . $aria_describedby . '>' . wp_kses_post($value) . '</textarea>';
166 + echo '<textarea id="' . $field_id . '" name="' . esc_html($field_name) . '" rows="3" class="' . esc_html($input_class) . '" placeholder="' . esc_html($placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>' . wp_kses_post($value) . '</textarea>';
167 167 break;
168 168 case 'select':
169 - echo '<select id="' . $field_id . '" name="' . $field_name . '" class="' . $select_class . '" ' . $required . ' ' . $aria_describedby . '>';
169 + echo '<select id="' . $field_id . '" name="' . esc_html($field_name) . '" class="' . esc_html($select_class) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
170 170 if (!empty($field_config['options']) && is_array($field_config['options'])) {
171 171 foreach ($field_config['options'] as $opt_val => $opt_label) {
172 172 echo '<option value="' . esc_attr($opt_val) . '" ' . selected($value, $opt_val, false) . '>' . esc_html($opt_label) . '</option>';
173 173 }
@@ -174,25 +174,25 @@
174 174 }
175 175 echo '</select>';
176 176 break;
177 177 case 'multiselect':
178 - echo '<select id="' . $field_id . '" name="' . $field_name . '[]" class="' . $select_class . '" multiple="multiple" aria-label="' . esc_attr($label) . '">';
178 + echo '<select id="' . $field_id . '" name="' . esc_html($field_name) . '[]" class="' . esc_html($select_class) . '" multiple="multiple" aria-label="' . esc_attr($label) . '">';
179 179 if (!empty($field_config['options']) && is_array($field_config['options'])) {
180 180 foreach ($field_config['options'] as $opt_val => $opt_label) {
181 181 $selected = is_array($value) && in_array($opt_val, $value) ? 'selected="selected"' : '';
182 - echo '<option value="' . esc_attr($opt_val) . '" ' . $selected . '>' . esc_html($opt_label) . '</option>';
182 + echo '<option value="' . esc_attr($opt_val) . '" ' . esc_html($selected) . '>' . esc_html($opt_label) . '</option>';
183 183 }
184 184 }
185 185 echo '</select>';
186 186 break;
187 187 case 'readonly':
188 - echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . $input_class . ' bg-gray-50" readonly ' . $aria_describedby . '>';
189 - echo '<input type="hidden" name="' . $field_name . '" value="' . esc_attr($value) . '">';
188 + echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . esc_html($input_class) . ' bg-gray-50" readonly ' . $aria_describedby . '>';
189 + echo '<input type="hidden" name="' . esc_html($field_name) . '" value="' . esc_attr($value) . '">';
190 190 break;
191 191 case 'checkbox': // Checkboxes that don't use the special description layout
192 192 echo '<div class="flex items-center">'; // Original 'tax_enabled' was just this simple structure
193 - echo ' <input type="checkbox" name="' . $field_name . '" id="' . $field_id . '" value="yes" ' . checked($value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded" ' . $required . ' ' . $aria_describedby . '>';
194 - echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . $label . '</label>';
193 + echo ' <input type="checkbox" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="yes" ' . checked($value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded" ' . esc_html($required) . ' ' . $aria_describedby . '>';
194 + echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . esc_html($label) . '</label>';
195 195 echo '</div>';
196 196 if (!empty($description_text)) { // Show description below the field
197 197 echo '<p id="' . $field_id . '-description" class="mt-2 text-sm text-gray-400 leading-relaxed">' . wp_kses($description_text, array(
198 198 'a' => array(
@@ -205,14 +205,14 @@
205 205 break;
206 206 case 'image':
207 207 echo '<div class="mt-1 flex items-center">';
208 208 echo ' <span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">';
209 - echo ' <img id="' . $field_id . '-preview" src="' . esc_url($value) . '" alt="' . esc_attr($label) . '" class="h-full w-full object-cover' . (empty($value) ? ' hidden' : '') . '">';
209 + echo ' <img id="' . $field_id . '-preview"' . (empty($value) ? '' : ' src="' . esc_url($value) . '"') . ' alt="' . esc_attr($label) . '" class="h-full w-full object-cover' . (empty($value) ? ' hidden' : '') . '">';
210 210 echo ' </span>';
211 211 echo ' <button type="button" id="upload_image_button_' . $field_id . '" class="upload-logo-button ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-uploader_title="' . esc_attr__('Choose Logo', 'easy-invoice') . '" data-uploader_button_text="' . esc_attr__('Select Logo', 'easy-invoice') . '">';
212 212 echo esc_html__('Change', 'easy-invoice');
213 213 echo '</button>';
214 - echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '" ' . $required . ' ' . $aria_describedby . '>';
214 + echo ' <input type="hidden" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($value) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
215 215 echo '</div>';
216 216 break;
217 217 case 'wp_editor':
218 218 // For wp_editor, the label is usually handled before calling it.
@@ -241,15 +241,15 @@
241 241 echo ' <div id="' . $field_id . '_result" class="mt-2" style="display: none;"></div>';
242 242 echo '</div>';
243 243 break;
244 244 case 'color':
245 - echo '<input type="color" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="h-10 w-20 border border-gray-300 rounded">';
245 + echo '<input type="color" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="h-10 w-20 border border-gray-300 rounded">';
246 246 break;
247 247 case 'range':
248 248 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
249 249 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
250 250 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
251 - echo '<input type="range" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '"' . $min . $max . $step . ' class="w-full">';
251 + echo '<input type="range" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($value) . '"' . $min . $max . $step . ' class="w-full">';
252 252 echo '<span class="text-sm text-gray-400">' . esc_html($value) . '%</span>';
253 253 break;
254 254 case 'button':
255 255 $button_text = $field_config['button_text'] ?? $label;
@@ -257,9 +257,9 @@
257 257 $button_class_name = 'regenerate-invoice-numbers-button';
258 258 if ($option_key === 'easy_invoice_regenerate_quote_numbers') {
259 259 $button_class_name = 'regenerate-quote-numbers-button';
260 260 }
261 - echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' ' . $button_class_name . '">';
261 + echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' ' . wp_kses_post($button_class_name) . '">';
262 262 echo esc_html($button_text);
263 263 echo '</button>';
264 264 break;
265 265 case 'image_upload':
@@ -264,9 +264,9 @@
264 264 break;
265 265 case 'image_upload':
266 266 echo '<div class="image-upload-wrap">';
267 267 echo '<div class="flex items-center space-x-3">';
268 - echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '">';
268 + echo ' <input type="hidden" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($value) . '">';
269 269 echo ' <button type="button" class="upload-image-button bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-target="' . $field_id . '">';
270 270 echo esc_html__('Upload Image', 'easy-invoice');
271 271 echo '</button>';
272 272 echo '</div>';
@@ -291,9 +291,9 @@
291 291 echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' regenerate-quote-numbers-button">';
292 292 echo esc_html($button_text);
293 293 echo '</button>';
294 294 } else {
295 - echo '<input type="text" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . $input_class . '" placeholder="' . $placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
295 + echo '<input type="text" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . esc_html($input_class) . '" placeholder="' . esc_html($placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
296 296 }
297 297 break;
298 298 }
299 299 // General description for non-checkbox and non-wp_editor fields (if it exists and not handled by special layouts)
@@ -315,9 +315,9 @@
315 315 * Note: This filter is already applied in the controller, so this is redundant
316 316 */
317 317 // $settings_config = apply_filters('easy_invoice_settings_fields_config', $settings_config);
318 318
319 -$active_section = $_GET['section'] ?? key($settings_config);
319 +$active_section = isset($_GET['section']) ? sanitize_key(wp_unslash($_GET['section'])) : key($settings_config); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
320 320 if (!isset($settings_config[$active_section])) {
321 321 $active_section = key($settings_config);
322 322 }
323 323 ?>
@@ -375,11 +375,11 @@
375 375 // Only show active subsection if we're actually on an email settings page
376 376 $active_email_subsection = null;
377 377 if ($active_section === 'email') {
378 378 if (isset($_GET['subsection']) && isset($section_data['subsections'][$_GET['subsection']])) {
379 - $active_email_subsection = $_GET['subsection'];
379 + $active_email_subsection = sanitize_key(wp_unslash($_GET['subsection'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
380 380 } elseif (!empty($_GET['subsection']) && isset($section_data['subsections'][$_GET['subsection']])) {
381 - $active_email_subsection = $_GET['subsection'];
381 + $active_email_subsection = sanitize_key(wp_unslash($_GET['subsection'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
382 382 } else {
383 383 // Default to 'general' only if we're on email section but no specific subsection
384 384 $active_email_subsection = 'general';
385 385 }
@@ -460,11 +460,11 @@
460 460 <?php
461 461 // Determine the active subsection from the hash or default to 'general'
462 462 $active_email_subsection = 'general';
463 463 if (isset($_GET['subsection']) && isset($section_data['subsections'][$_GET['subsection']])) {
464 - $active_email_subsection = $_GET['subsection'];
464 + $active_email_subsection = sanitize_key(wp_unslash($_GET['subsection'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
465 465 } elseif (!empty($_GET['subsection']) && isset($section_data['subsections'][$_GET['subsection']])) {
466 - $active_email_subsection = $_GET['subsection'];
466 + $active_email_subsection = sanitize_key(wp_unslash($_GET['subsection'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
467 467 }
468 468 if (!isset($section_data['subsections'][$active_email_subsection])) {
469 469 $active_email_subsection = array_key_first($section_data['subsections']);
470 470 }
@@ -474,9 +474,9 @@
474 474 // Render all email subsections so JS can show/hide them
475 475 foreach ($section_data['subsections'] as $subsection_key => $subsection_data) {
476 476 $is_active = ($subsection_key === $active_email_subsection) ? '' : 'hidden';
477 477 ?>
478 - <div id="email--<?php echo esc_attr($subsection_key); ?>-content" class="email-subsection-content <?php echo $is_active; ?>">
478 + <div id="email--<?php echo esc_attr($subsection_key); ?>-content" class="email-subsection-content <?php echo esc_attr($is_active); ?>">
479 479 <?php
480 480 // Display subsection title
481 481 $subsection_title = '';
482 482 switch ($subsection_key) {
@@ -536,9 +536,9 @@
536 536 <?php if (!empty($notice['title'])): ?>
537 537 <h4 class="text-sm font-semibold <?php echo esc_attr($c['title']); ?>"><?php echo esc_html($notice['title']); ?></h4>
538 538 <?php endif; ?>
539 539 <?php if (!empty($notice['message'])): ?>
540 - <p class="mt-1 text-sm <?php echo esc_attr($c['body']); ?>"><?php echo esc_html($notice['message']); ?></p>
540 + <p class="mt-1 text-sm <?php echo esc_attr($c['body']); ?>"><?php echo wp_kses_post($notice['message']); ?></p>
541 541 <?php endif; ?>
542 542 <?php if (!empty($notice['cta_url']) && !empty($notice['cta_label'])): ?>
543 543 <p class="mt-3">
544 544 <a href="<?php echo esc_url($notice['cta_url']); ?>" class="inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700">
@@ -564,9 +564,9 @@
564 564 $select_class = 'mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md';
565 565 $col_span_class = esc_attr($field_config['col_span'] ?? 'sm:col-span-6');
566 566 echo '<div class="field-wrapper form-group">';
567 567 if ($field_type !== 'checkbox') {
568 - echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700">' . $field_label . '</label>';
568 + echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700">' . esc_html($field_label) . '</label>';
569 569 }
570 570
571 571 // Define required and aria_describedby variables
572 572 $required = !empty($field_config['required']) ? 'required' : '';
@@ -576,21 +576,21 @@
576 576 case 'text':
577 577 case 'email':
578 578 case 'url':
579 579 case 'tel':
580 - echo '<input type="' . esc_attr($field_type) . '" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
580 + echo '<input type="' . esc_attr($field_type) . '" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . esc_html($input_class) . '" placeholder="' . esc_html($field_placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
581 581 break;
582 582 case 'number':
583 583 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
584 584 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
585 585 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
586 - echo '<input type="number" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
586 + echo '<input type="number" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . esc_html($input_class) . '" placeholder="' . esc_html($field_placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
587 587 break;
588 588 case 'textarea':
589 - echo '<textarea id="' . $field_id . '" name="' . $field_name . '" rows="3" class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>' . wp_kses_post($current_value) . '</textarea>';
589 + echo '<textarea id="' . $field_id . '" name="' . esc_html($field_name) . '" rows="3" class="' . esc_html($input_class) . '" placeholder="' . esc_html($field_placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>' . wp_kses_post($current_value) . '</textarea>';
590 590 break;
591 591 case 'select':
592 - echo '<select id="' . $field_id . '" name="' . $field_name . '" class="' . $select_class . '" ' . $required . ' ' . $aria_describedby . '>';
592 + echo '<select id="' . $field_id . '" name="' . esc_html($field_name) . '" class="' . esc_html($select_class) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
593 593 if (!empty($field_config['options']) && is_array($field_config['options'])) {
594 594 foreach ($field_config['options'] as $opt_val => $opt_label) {
595 595 echo '<option value="' . esc_attr($opt_val) . '" ' . selected($current_value, $opt_val, false) . '>' . esc_html($opt_label) . '</option>';
596 596 }
@@ -597,25 +597,25 @@
597 597 }
598 598 echo '</select>';
599 599 break;
600 600 case 'multiselect':
601 - echo '<select id="' . $field_id . '" name="' . $field_name . '[]" class="' . $select_class . '" multiple="multiple" aria-label="' . esc_attr($field_label) . '">';
601 + echo '<select id="' . $field_id . '" name="' . esc_html($field_name) . '[]" class="' . esc_html($select_class) . '" multiple="multiple" aria-label="' . esc_attr($field_label) . '">';
602 602 if (!empty($field_config['options']) && is_array($field_config['options'])) {
603 603 foreach ($field_config['options'] as $opt_val => $opt_label) {
604 604 $selected = is_array($current_value) && in_array($opt_val, $current_value) ? 'selected="selected"' : '';
605 - echo '<option value="' . esc_attr($opt_val) . '" ' . $selected . '>' . esc_html($opt_label) . '</option>';
605 + echo '<option value="' . esc_attr($opt_val) . '" ' . esc_html($selected) . '>' . esc_html($opt_label) . '</option>';
606 606 }
607 607 }
608 608 echo '</select>';
609 609 break;
610 610 case 'readonly':
611 - echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . ' bg-gray-50" readonly>';
612 - echo '<input type="hidden" name="' . $field_name . '" value="' . esc_attr($current_value) . '">';
611 + echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . esc_html($input_class) . ' bg-gray-50" readonly>';
612 + echo '<input type="hidden" name="' . esc_html($field_name) . '" value="' . esc_attr($current_value) . '">';
613 613 break;
614 614 case 'checkbox':
615 615 echo '<div class="flex items-center">';
616 - echo ' <input type="checkbox" name="' . $field_name . '" id="' . $field_id . '" value="yes" ' . checked($current_value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">';
617 - echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . $field_label . '</label>';
616 + echo ' <input type="checkbox" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="yes" ' . checked($current_value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">';
617 + echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . esc_html($field_label) . '</label>';
618 618 echo '</div>';
619 619 if (!empty($field_description)) {
620 620 echo '<p id="' . $field_id . '-description" class="mt-2 text-sm text-gray-400 leading-relaxed">' . esc_html($field_description) . '</p>';
621 621 }
@@ -622,14 +622,14 @@
622 622 break;
623 623 case 'image':
624 624 echo '<div class="mt-1 flex items-center">';
625 625 echo ' <span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">';
626 - echo ' <img id="' . $field_id . '-preview" src="' . esc_url($current_value) . '" alt="' . esc_attr($field_label) . '" class="h-full w-full object-cover' . (empty($current_value) ? ' hidden' : '') . '">';
626 + echo ' <img id="' . $field_id . '-preview"' . (empty($current_value) ? '' : ' src="' . esc_url($current_value) . '"') . ' alt="' . esc_attr($field_label) . '" class="h-full w-full object-cover' . (empty($current_value) ? ' hidden' : '') . '">';
627 627 echo ' </span>';
628 628 echo ' <button type="button" id="upload_image_button_' . $field_id . '" class="upload-logo-button ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-uploader_title="' . esc_attr__('Choose Logo', 'easy-invoice') . '" data-uploader_button_text="' . esc_attr__('Select Logo', 'easy-invoice') . '">';
629 629 echo esc_html__('Change', 'easy-invoice');
630 630 echo '</button>';
631 - echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
631 + echo ' <input type="hidden" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
632 632 echo '</div>';
633 633 break;
634 634 case 'wp_editor':
635 635 wp_editor( $current_value, $field_id, ['textarea_name' => $field_name, 'teeny' => true, 'media_buttons' => false, 'textarea_rows' => 7, 'editor_class' => 'mt-1'] );
@@ -634,9 +634,9 @@
634 634 case 'wp_editor':
635 635 wp_editor( $current_value, $field_id, ['textarea_name' => $field_name, 'teeny' => true, 'media_buttons' => false, 'textarea_rows' => 7, 'editor_class' => 'mt-1'] );
636 636 // Handle description for wp_editor specifically
637 637 if (!empty($field_description)) {
638 - echo '<p class="mt-1 text-sm text-gray-400">' . esc_html($field_description) . '</p>';
638 + echo '<p id="' . $field_id . '-description" class="mt-1 text-sm text-gray-400">' . wp_kses($field_description, ['a' => ['href' => [], 'target' => [], 'class' => []], 'code' => [], 'strong' => [], 'em' => []]) . '</p>';
639 639 }
640 640 break;
641 641 case 'test_email':
642 642 echo '<div class="mt-1">';
@@ -655,10 +655,10 @@
655 655 $is_payment_test = ($field_id === 'easy_invoice_payment_test_template');
656 656 $width_class = $is_payment_test ? 'w-[200px]' : 'w-64';
657 657 echo '<div class="mt-1">';
658 658 echo ' <div class="flex items-center space-x-3">';
659 - echo ' <input type="email" id="' . $field_id . '_email" placeholder="' . esc_attr__('Enter email address to test', 'easy-invoice') . '" class="mt-1 block ' . $width_class . ' border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" value="' . esc_attr(get_option('admin_email')) . '">';
660 - echo ' <button type="button" id="' . $field_id . '_button" class="test-template-email-button inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 h-[38px]" data-template-type="' . esc_attr($template_type) . '">';
659 + echo ' <input type="email" id="' . $field_id . '_email" placeholder="' . esc_attr__('Enter email address to test', 'easy-invoice') . '" class="mt-1 block ' . esc_html($width_class) . ' border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" value="' . esc_attr(get_option('admin_email')) . '">';
660 + echo ' <button type="button" id="' . $field_id . '_button" data-template-type="' . esc_attr($field_config['template_type'] ?? '') . '" class="test-template-email-button inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 h-[38px]" data-template-type="' . esc_attr($template_type) . '">';
661 661 echo ' <i class="fas fa-envelope mr-2" aria-hidden="true"></i>';
662 662 echo ' ' . esc_html__('Test Template', 'easy-invoice');
663 663 echo ' </button>';
664 664 echo ' </div>';
@@ -677,13 +677,13 @@
677 677 echo ' <div id="' . $field_id . '_result" class="mt-2" style="display: none;"></div>';
678 678 echo '</div>';
679 679 break;
680 680 default:
681 - echo '<input type="text" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . $field_placeholder . '">';
681 + echo '<input type="text" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . esc_html($input_class) . '" placeholder="' . esc_html($field_placeholder) . '">';
682 682 break;
683 683 }
684 684 if ($field_type !== 'checkbox' && $field_type !== 'wp_editor' && !empty($field_description)) {
685 - echo '<p class="mt-1 text-sm text-gray-400">' . esc_html($field_description) . '</p>';
685 + echo '<p id="' . $field_id . '-description" class="mt-1 text-sm text-gray-400">' . wp_kses($field_description, ['a' => ['href' => [], 'target' => [], 'class' => []], 'code' => [], 'strong' => [], 'em' => []]) . '</p>';
686 686 }
687 687 echo '</div>'; // Close the field wrapper div
688 688 }
689 689 }
@@ -718,8 +718,9 @@
718 718 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{client_email}}</div>
719 719 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{client_address}}</div>
720 720 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{company_name}}</div>
721 721 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{total_amount}}</div>
722 + <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{amount_due}}</div>
722 723 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{issue_date}}</div>
723 724 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{company_email}}</div>
724 725 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{company_phone}}</div>
725 726 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{payment_terms}}</div>
@@ -737,9 +738,9 @@
737 738 <div class="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
738 739 <div class="flex items-center">
739 740 <i class="fas fa-info-circle text-blue-500 mr-2"></i>
740 741 <p class="text-sm text-blue-700">
741 - <?php _e('Drag and drop payment methods to reorder them. The order will be reflected on payment forms.', 'easy-invoice'); ?>
742 + <?php esc_html_e('Drag and drop payment methods to reorder them. The order will be reflected on payment forms.', 'easy-invoice'); ?>
742 743 </p>
743 744 </div>
744 745 </div>
745 746 <?php endif; ?>
@@ -818,9 +819,9 @@
818 819 count($pro_gateway_teasers)
819 820 );
820 821 ?>
821 822 </h3>
822 - <p class="mt-0.5 text-xs text-gray-500"><?php esc_html_e('Stripe, Square, Mollie, Paystack and more — installed alongside PayPal &amp; Manual.', 'easy-invoice'); ?></p>
823 + <p class="mt-0.5 text-xs text-gray-500"><?php esc_html_e('Stripe, Square, Mollie, Paystack and more — installed alongside PayPal and Manual.', 'easy-invoice'); ?></p>
823 824 </div>
824 825 </div>
825 826 <a href="https://matrixaddons.com/plugins/easy-invoice/#pricing" target="_blank" rel="noopener"
826 827 class="ml-4 shrink-0 inline-flex items-center px-3 py-1.5 rounded-md text-xs font-semibold text-white bg-indigo-600 hover:bg-indigo-700 transition-colors">
@@ -884,9 +885,9 @@
884 885 <label for="gateway-enable-<?php echo esc_attr($gateway_id); ?>" class="font-medium text-gray-900">
885 886 <?php echo esc_html(method_exists($gateway, 'getTitle') ? $gateway->getTitle() : $gateway_id); ?>
886 887 </label>
887 888 <?php if (method_exists($gateway, 'getDescription') && $gateway->getDescription()): ?>
888 - <span class="block text-sm text-gray-400"><?php echo esc_html($gateway->getDescription()); ?></span>
889 + <span class="block text-sm text-gray-400"><?php echo wp_kses_post($gateway->getDescription()); ?></span>
889 890 <?php endif; ?>
890 891 </div>
891 892 </div>
892 893
@@ -893,9 +894,9 @@
893 894
894 895 <div class="gateway-settings <?php echo empty($payment_methods_enabled) || !in_array($gateway_id, $payment_methods_enabled) ? 'hidden' : ''; ?>">
895 896 <div class="mb-4">
896 897 <label for="gateway-display-name-<?php echo esc_attr($gateway_id); ?>" class="block text-sm font-medium text-gray-700">
897 - <?php _e('Display Name', 'easy-invoice'); ?>
898 + <?php esc_html_e('Display Name', 'easy-invoice'); ?>
898 899 </label>
899 900 <input type="text"
900 901 id="gateway-display-name-<?php echo esc_attr($gateway_id); ?>"
901 902 name="settings[easy_invoice_gateway_display_name_<?php echo esc_attr($gateway_id); ?>]"
@@ -902,9 +903,9 @@
902 903 value="<?php echo esc_attr($settings['easy_invoice_gateway_display_name_' . $gateway_id] ?? (method_exists($gateway, 'getTitle') ? $gateway->getTitle() : ucfirst(str_replace('_', ' ', $gateway_id)))); ?>"
903 904 placeholder="<?php echo esc_attr(method_exists($gateway, 'getTitle') ? $gateway->getTitle() : ucfirst(str_replace('_', ' ', $gateway_id))); ?>"
904 905 class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
905 906 <p class="mt-1 text-xs text-gray-500">
906 - <?php _e('Leave blank to use the default name. This name will appear on invoices and payment forms.', 'easy-invoice'); ?>
907 + <?php esc_html_e('Leave blank to use the default name. This name will appear on invoices and payment forms.', 'easy-invoice'); ?>
907 908 </p>
908 909 </div>
909 910
910 911 <?php
@@ -986,18 +987,18 @@
986 987 case 'text':
987 988 case 'email':
988 989 case 'url':
989 990 case 'tel':
990 - echo '<input type="' . esc_attr($field_config['type']) . '" name="settings[' . esc_attr($tax_key) . ']" id="' . esc_attr($tax_key) . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . esc_attr($field_config['placeholder'] ?? '') . '">';
991 + echo '<input type="' . esc_attr($field_config['type']) . '" name="settings[' . esc_attr($tax_key) . ']" id="' . esc_attr($tax_key) . '" value="' . esc_attr($current_value) . '" class="' . esc_html($input_class) . '" placeholder="' . esc_attr($field_config['placeholder'] ?? '') . '">';
991 992 break;
992 993 case 'number':
993 994 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
994 995 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
995 996 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
996 - echo '<input type="number" name="settings[' . esc_attr($tax_key) . ']" id="' . esc_attr($tax_key) . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . $input_class . '" placeholder="' . esc_attr($field_config['placeholder'] ?? '') . '">';
997 + echo '<input type="number" name="settings[' . esc_attr($tax_key) . ']" id="' . esc_attr($tax_key) . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . esc_html($input_class) . '" placeholder="' . esc_attr($field_config['placeholder'] ?? '') . '">';
997 998 break;
998 999 case 'select':
999 - echo '<select id="' . esc_attr($tax_key) . '" name="settings[' . esc_attr($tax_key) . ']" class="' . $select_class . '">';
1000 + echo '<select id="' . esc_attr($tax_key) . '" name="settings[' . esc_attr($tax_key) . ']" class="' . esc_html($select_class) . '">';
1000 1001 if (!empty($field_config['options']) && is_array($field_config['options'])) {
1001 1002 foreach ($field_config['options'] as $opt_val => $opt_label) {
1002 1003 echo '<option value="' . esc_attr($opt_val) . '" ' . selected($current_value, $opt_val, false) . '>' . esc_html($opt_label) . '</option>';
1003 1004 }
@@ -1015,12 +1016,13 @@
1015 1016 // Allow additional fields to be added to the tax section
1016 1017 $additional_tax_fields = apply_filters('easy_invoice_tax_section_additional_fields', [], $settings);
1017 1018 if (!empty($additional_tax_fields)) {
1018 1019 echo '<div class="mt-6 pt-6 border-t border-gray-200">';
1019 - echo '<h4 class="text-sm font-medium text-gray-900 mb-4">' . __('Additional Tax Settings', 'easy-invoice-pro') . '</h4>';
1020 + echo '<h4 class="text-sm font-medium text-gray-900 mb-4">' . esc_html__('Additional Tax Settings', 'easy-invoice') . '</h4>';
1020 1021 echo '<div class="grid grid-cols-1 md:grid-cols-2 gap-6">';
1021 1022 foreach ($additional_tax_fields as $field_key => $field_config) {
1022 - $current_value = $settings[$field_key] ?? ($field_config['default'] ?? '');
1023 + // Filter-only fields are not in the loaded settings array; read the option itself.
1024 + $current_value = array_key_exists($field_key, (array) $settings) ? $settings[$field_key] : get_option($field_key, $field_config['default'] ?? '');
1023 1025 easy_invoice_render_field($field_key, $field_config, $current_value);
1024 1026 }
1025 1027 echo '</div>';
1026 1028 echo '</div>';
@@ -1069,11 +1071,11 @@
1069 1071 $conditional_class .= ' depends-on-' . esc_attr($depends_key) . '-' . esc_attr($depends_value);
1070 1072 }
1071 1073 }
1072 1074
1073 - echo '<div class="form-group ' . $form_group_class . $conditional_class . '">';
1075 + echo '<div class="form-group ' . esc_html($form_group_class) . esc_html($conditional_class) . '">';
1074 1076 if ($field_type !== 'checkbox') {
1075 - echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700">' . $field_label . '</label>';
1077 + echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700">' . esc_html($field_label) . '</label>';
1076 1078 }
1077 1079
1078 1080 // Define required and aria_describedby variables
1079 1081 $required = !empty($field_config['required']) ? 'required' : '';
@@ -1083,21 +1085,21 @@
1083 1085 case 'text':
1084 1086 case 'email':
1085 1087 case 'url':
1086 1088 case 'tel':
1087 - echo '<input type="' . esc_attr($field_type) . '" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
1089 + echo '<input type="' . esc_attr($field_type) . '" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . esc_html($input_class) . '" placeholder="' . esc_html($field_placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
1088 1090 break;
1089 1091 case 'number':
1090 1092 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
1091 1093 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
1092 1094 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
1093 - echo '<input type="number" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
1095 + echo '<input type="number" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . esc_html($input_class) . '" placeholder="' . esc_html($field_placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
1094 1096 break;
1095 1097 case 'textarea':
1096 - echo '<textarea id="' . $field_id . '" name="' . $field_name . '" rows="3" class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>' . wp_kses_post($current_value) . '</textarea>';
1098 + echo '<textarea id="' . $field_id . '" name="' . esc_html($field_name) . '" rows="3" class="' . esc_html($input_class) . '" placeholder="' . esc_html($field_placeholder) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>' . wp_kses_post($current_value) . '</textarea>';
1097 1099 break;
1098 1100 case 'select':
1099 - echo '<select id="' . $field_id . '" name="' . $field_name . '" class="' . $select_class . '" ' . $required . ' ' . $aria_describedby . '>';
1101 + echo '<select id="' . $field_id . '" name="' . esc_html($field_name) . '" class="' . esc_html($select_class) . '" ' . esc_html($required) . ' ' . $aria_describedby . '>';
1100 1102 if (!empty($field_config['options']) && is_array($field_config['options'])) {
1101 1103 foreach ($field_config['options'] as $opt_val => $opt_label) {
1102 1104 echo '<option value="' . esc_attr($opt_val) . '" ' . selected(strtolower($current_value), strtolower($opt_val), false) . '>' . esc_html($opt_label) . '</option>';
1103 1105 }
@@ -1104,25 +1106,25 @@
1104 1106 }
1105 1107 echo '</select>';
1106 1108 break;
1107 1109 case 'multiselect':
1108 - echo '<select id="' . $field_id . '" name="' . $field_name . '[]" class="' . $select_class . '" multiple="multiple" aria-label="' . esc_attr($field_label) . '">';
1110 + echo '<select id="' . $field_id . '" name="' . esc_html($field_name) . '[]" class="' . esc_html($select_class) . '" multiple="multiple" aria-label="' . esc_attr($field_label) . '">';
1109 1111 if (!empty($field_config['options']) && is_array($field_config['options'])) {
1110 1112 foreach ($field_config['options'] as $opt_val => $opt_label) {
1111 1113 $selected = is_array($current_value) && in_array($opt_val, $current_value) ? 'selected="selected"' : '';
1112 - echo '<option value="' . esc_attr($opt_val) . '" ' . $selected . '>' . esc_html($opt_label) . '</option>';
1114 + echo '<option value="' . esc_attr($opt_val) . '" ' . esc_html($selected) . '>' . esc_html($opt_label) . '</option>';
1113 1115 }
1114 1116 }
1115 1117 echo '</select>';
1116 1118 break;
1117 1119 case 'readonly':
1118 - echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . ' bg-gray-50" readonly>';
1119 - echo '<input type="hidden" name="' . $field_name . '" value="' . esc_attr($current_value) . '">';
1120 + echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . esc_html($input_class) . ' bg-gray-50" readonly>';
1121 + echo '<input type="hidden" name="' . esc_html($field_name) . '" value="' . esc_attr($current_value) . '">';
1120 1122 break;
1121 1123 case 'checkbox':
1122 1124 echo '<div class="flex items-center">';
1123 - echo ' <input type="checkbox" name="' . $field_name . '" id="' . $field_id . '" value="yes" ' . checked($current_value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">';
1124 - echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . $field_label . '</label>';
1125 + echo ' <input type="checkbox" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="yes" ' . checked($current_value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">';
1126 + echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . esc_html($field_label) . '</label>';
1125 1127 echo '</div>';
1126 1128 if (!empty($field_description)) {
1127 1129 echo '<p id="' . $field_id . '-description" class="mt-2 text-sm text-gray-400 leading-relaxed">' . esc_html($field_description) . '</p>';
1128 1130 }
@@ -1129,14 +1131,14 @@
1129 1131 break;
1130 1132 case 'image':
1131 1133 echo '<div class="mt-1 flex items-center">';
1132 1134 echo ' <span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">';
1133 - echo ' <img id="' . $field_id . '-preview" src="' . esc_url($current_value) . '" alt="' . esc_attr($field_label) . '" class="h-full w-full object-cover' . (empty($current_value) ? ' hidden' : '') . '">';
1135 + echo ' <img id="' . $field_id . '-preview"' . (empty($current_value) ? '' : ' src="' . esc_url($current_value) . '"') . ' alt="' . esc_attr($field_label) . '" class="h-full w-full object-cover' . (empty($current_value) ? ' hidden' : '') . '">';
1134 1136 echo ' </span>';
1135 1137 echo ' <button type="button" id="upload_image_button_' . $field_id . '" class="upload-logo-button ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-uploader_title="' . esc_attr__('Choose Logo', 'easy-invoice') . '" data-uploader_button_text="' . esc_attr__('Select Logo', 'easy-invoice') . '">';
1136 1138 echo esc_html__('Change', 'easy-invoice');
1137 1139 echo '</button>';
1138 - echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
1140 + echo ' <input type="hidden" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
1139 1141 echo '</div>';
1140 1142 break;
1141 1143 case 'wp_editor':
1142 1144 wp_editor( $current_value, $field_id, ['textarea_name' => $field_name, 'teeny' => true, 'media_buttons' => false, 'textarea_rows' => 7, 'editor_class' => 'mt-1'] );
@@ -1141,25 +1143,25 @@
1141 1143 case 'wp_editor':
1142 1144 wp_editor( $current_value, $field_id, ['textarea_name' => $field_name, 'teeny' => true, 'media_buttons' => false, 'textarea_rows' => 7, 'editor_class' => 'mt-1'] );
1143 1145 // Handle description for wp_editor specifically
1144 1146 if (!empty($field_description)) {
1145 - echo '<p class="mt-1 text-sm text-gray-400">' . esc_html($field_description) . '</p>';
1147 + echo '<p id="' . $field_id . '-description" class="mt-1 text-sm text-gray-400">' . wp_kses($field_description, ['a' => ['href' => [], 'target' => [], 'class' => []], 'code' => [], 'strong' => [], 'em' => []]) . '</p>';
1146 1148 }
1147 1149 break;
1148 1150 case 'color':
1149 - echo '<input type="color" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="h-10 w-20 border border-gray-300 rounded">';
1151 + echo '<input type="color" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="h-10 w-20 border border-gray-300 rounded">';
1150 1152 break;
1151 1153 case 'range':
1152 1154 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
1153 1155 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
1154 1156 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
1155 - echo '<input type="range" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="w-full">';
1157 + echo '<input type="range" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="w-full">';
1156 1158 echo '<span class="text-sm text-gray-400">' . esc_html($current_value) . '%</span>';
1157 1159 break;
1158 1160 case 'image_upload':
1159 1161 echo '<div class="image-upload-wrap">';
1160 1162 echo '<div class="flex items-center space-x-3">';
1161 - echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
1163 + echo ' <input type="hidden" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
1162 1164 echo ' <button type="button" class="upload-image-button bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-target="' . $field_id . '">';
1163 1165 echo esc_html__('Upload Image', 'easy-invoice');
1164 1166 echo '</button>';
1165 1167 echo '</div>';
@@ -1176,18 +1178,18 @@
1176 1178 $button_class_name = 'regenerate-invoice-numbers-button';
1177 1179 if ($option_key === 'easy_invoice_regenerate_quote_numbers') {
1178 1180 $button_class_name = 'regenerate-quote-numbers-button';
1179 1181 }
1180 - echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' ' . $button_class_name . '">';
1182 + echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' ' . wp_kses_post($button_class_name) . '">';
1181 1183 echo esc_html($button_text);
1182 1184 echo '</button>';
1183 1185 break;
1184 1186 default:
1185 - echo '<input type="text" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . $field_placeholder . '">';
1187 + echo '<input type="text" name="' . esc_html($field_name) . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . esc_html($input_class) . '" placeholder="' . esc_html($field_placeholder) . '">';
1186 1188 break;
1187 1189 }
1188 1190 if ($field_type !== 'checkbox' && $field_type !== 'wp_editor' && !empty($field_description)) {
1189 - echo '<p class="mt-1 text-sm text-gray-400">' . esc_html($field_description) . '</p>';
1191 + echo '<p id="' . $field_id . '-description" class="mt-1 text-sm text-gray-400">' . wp_kses($field_description, ['a' => ['href' => [], 'target' => [], 'class' => []], 'code' => [], 'strong' => [], 'em' => []]) . '</p>';
1190 1192 }
1191 1193 echo '</div>';
1192 1194 }
1193 1195 if ($is_grid) echo '</div>';