| @@ -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 & 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>'; |