$method_name($field, $invoice); } // Fallback to text field return $this->renderTextField($field, $invoice); } /** * Render a text field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderTextField(array $field, $invoice = null): string { $id = $field['id'] ?? $field['name'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $placeholder = $field['placeholder'] ?? ''; $required = $field['required'] ?? false; $readonly = $field['readonly'] ?? false; $description = $field['description'] ?? ''; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $required_attr = $required ? 'required' : ''; $required_class = $required ? 'required' : ''; $readonly_attr = $readonly ? 'readonly' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($required_class), esc_html($label), esc_attr($id), esc_attr($name), esc_attr($value), esc_attr($placeholder), esc_attr($required_class), $required_attr, $readonly_attr, $description_html ); } /** * Render a hidden field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderHiddenField(array $field, $invoice = null): string { $id = $field['id'] ?? ''; $name = $field['name'] ?? ''; $value = $this->getFieldValue($field, $invoice); return sprintf( '', esc_attr($id), esc_attr($name), esc_attr($value) ); } /** * Render an email field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderEmailField(array $field, $invoice = null): string { $id = $field['id'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $placeholder = $field['placeholder'] ?? ''; $required = $field['required'] ?? false; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $description = $field['description'] ?? ''; $required_attr = $required ? 'required' : ''; $required_class = $required ? 'required' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($required_class), esc_html($label), esc_attr($id), esc_attr($name), esc_attr($value), esc_attr($placeholder), esc_attr($required_class), $required_attr, $description_html ); } /** * Render a telephone field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderTelField(array $field, $invoice = null): string { $id = $field['id'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $placeholder = $field['placeholder'] ?? ''; $required = $field['required'] ?? false; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $description = $field['description'] ?? ''; $required_attr = $required ? 'required' : ''; $required_class = $required ? 'required' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($required_class), esc_html($label), esc_attr($id), esc_attr($name), esc_attr($value), esc_attr($placeholder), esc_attr($required_class), $required_attr, $description_html ); } /** * Render a URL field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderUrlField(array $field, $invoice = null): string { $id = $field['id'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $placeholder = $field['placeholder'] ?? ''; $required = $field['required'] ?? false; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $description = $field['description'] ?? ''; $required_attr = $required ? 'required' : ''; $required_class = $required ? 'required' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($required_class), esc_html($label), esc_attr($id), esc_attr($name), esc_attr($value), esc_attr($placeholder), esc_attr($required_class), $required_attr, $description_html ); } /** * Render a date field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderDateField(array $field, $invoice = null): string { $id = $field['id'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $placeholder = $field['placeholder'] ?? ''; $required = $field['required'] ?? false; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $description = $field['description'] ?? ''; $required_attr = $required ? 'required' : ''; $required_class = $required ? 'required' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($required_class), esc_html($label), esc_attr($id), esc_attr($name), esc_attr($value), esc_attr($placeholder), esc_attr($required_class), $required_attr, $description_html ); } /** * Render a number field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderNumberField(array $field, $invoice = null): string { $id = $field['id'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $placeholder = $field['placeholder'] ?? ''; $required = $field['required'] ?? false; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $min = $field['min'] ?? ''; $max = $field['max'] ?? ''; $step = $field['step'] ?? ''; $description = $field['description'] ?? ''; $required_attr = $required ? 'required' : ''; $required_class = $required ? 'required' : ''; $min_attr = $min !== '' ? 'min="' . esc_attr($min) . '"' : ''; $max_attr = $max !== '' ? 'max="' . esc_attr($max) . '"' : ''; $step_attr = $step !== '' ? 'step="' . esc_attr($step) . '"' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($required_class), esc_html($label), esc_attr($id), esc_attr($name), esc_attr($value), esc_attr($placeholder), esc_attr($required_class), $required_attr, $min_attr, $max_attr, $step_attr, $description_html ); } /** * Render a select field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderSelectField(array $field, $invoice = null): string { $id = $field['id'] ?? $field['name'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $required = $field['required'] ?? false; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $options = $field['options'] ?? []; $description = $field['description'] ?? ''; $required_attr = $required ? 'required' : ''; $required_class = $required ? 'required' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; $options_html = ''; foreach ($options as $option_value => $option_label) { $selected = ($value == $option_value) ? 'selected' : ''; $options_html .= sprintf( '', esc_attr($option_value), $selected, esc_html($option_label) ); } return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($required_class), esc_html($label), esc_attr($id), esc_attr($name), esc_attr($required_class), $required_attr, $options_html, $description_html ); } /** * Render a textarea field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderTextareaField(array $field, $invoice = null): string { $id = $field['id'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $placeholder = $field['placeholder'] ?? ''; $required = $field['required'] ?? false; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $rows = $field['rows'] ?? 3; $description = $field['description'] ?? ''; $required_attr = $required ? 'required' : ''; $required_class = $required ? 'required' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($required_class), esc_html($label), esc_attr($id), esc_attr($name), esc_attr($rows), esc_attr($placeholder), esc_attr($required_class), $required_attr, wp_kses_post($value), $description_html ); } /** * Render a checkbox field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderCheckboxField(array $field, $invoice = null): string { $id = $field['id'] ?? $field['name'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $description = $field['description'] ?? ''; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $value = $this->getFieldValue($field, $invoice); $checked = $value ? 'checked' : ''; $description_html = $description ? '

' . esc_html($description) . '

' : ''; return sprintf( '
%s
', esc_attr($grid_cols), esc_attr($id), esc_attr($name), $checked, esc_attr($id), esc_html($label), $description_html ); } /** * Render a notice field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderNoticeField(array $field, $invoice = null): string { $label = $field['label'] ?? ''; $description = $field['description'] ?? ''; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-6'; $notice_type = $field['notice_type'] ?? 'info'; // Set notice colors based on type $notice_classes = [ 'info' => 'bg-blue-50 border-blue-200 text-blue-700', 'warning' => 'bg-yellow-50 border-yellow-200 text-yellow-700', 'error' => 'bg-red-50 border-red-200 text-red-700', 'success' => 'bg-green-50 border-green-200 text-green-700' ]; $notice_class = $notice_classes[$notice_type] ?? $notice_classes['info']; return sprintf( '

%s

%s

', esc_attr($grid_cols), esc_attr($notice_class), esc_html($label), esc_html($description) ); } /** * Render a payment gateways field * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Rendered HTML */ private function renderPaymentGatewaysField(array $field, $invoice = null): string { $id = $field['id'] ?? ''; $name = $field['name'] ?? ''; $label = $field['label'] ?? ''; $description = $field['description'] ?? ''; $grid_cols = $field['grid_cols'] ?? 'sm:col-span-12'; $value = $this->getFieldValue($field, $invoice); // Get enabled payment gateways from the main plugin instance $payment_manager = \EasyInvoice\EasyInvoice::getInstance()->getGatewayManager(); $enabled_gateways = $payment_manager->getEnabledGateways(); // Convert saved value to array if it's a string $selected_gateways = []; $has_custom_selection = false; if (!empty($value)) { if (is_string($value)) { $selected_gateways = explode(',', $value); } elseif (is_array($value)) { $selected_gateways = $value; } $has_custom_selection = !empty($selected_gateways); } // Check if toggle state is enabled (either from selected gateways or toggle state field) $toggle_enabled = $has_custom_selection; if ($invoice && method_exists($invoice, 'getPaymentGatewaysToggleState')) { $toggle_state = $invoice->getPaymentGatewaysToggleState(); if ($toggle_state === '1') { $toggle_enabled = true; } } // Section heading with icon (fixed size) - will be shown/hidden via JavaScript $section_heading = ''; $description_html = ''; if ($description) { $description_html = '

' . esc_html($description) . '

'; } $gateways_html = ''; if (empty($enabled_gateways)) { $gateways_html = '
' . __('No payment gateways are currently enabled. Please enable gateways in the plugin settings.', 'easy-invoice') . '
'; } else { // Show current status only when toggle is on and gateways are selected if ($has_custom_selection) { $gateway_names = array_map(function($gateway) { return $gateway->getTitle(); }, $enabled_gateways); $gateways_html .= '
'; $gateways_html .= ''; $selected_names = array_map(function($gateway) use ($enabled_gateways) { return $enabled_gateways[$gateway]->getTitle(); }, $selected_gateways); $gateways_html .= '
' . __('Restricted to:', 'easy-invoice') . ' ' . esc_html(implode(', ', $selected_names)) . '
'; $gateways_html .= '
'; } // Switch-style toggle for custom selection - improved visibility and design $gateways_html .= '
'; $gateways_html .= ''; $gateways_html .= '
' . __('By default, all payment methods are available. Enable this option to select specific methods - unchecked items will not appear during payment.', 'easy-invoice') . '
'; $gateways_html .= '
'; // Hidden field for selected gateways $initial_gateways_value = $has_custom_selection ? implode(',', $selected_gateways) : ''; $gateways_html .= ''; // Gateway cards (no icon, minimal, modern) - only show when toggle is enabled $gateways_html .= ''; // Add JavaScript to handle toggle and card clicks $gateways_html .= ''; } return sprintf( '
%s
%s %s
', esc_attr($grid_cols), $section_heading, $description_html, $gateways_html ); } /** * Get field value from invoice or default * * @since 1.0.0 * @param array $field Field configuration * @param mixed $invoice Invoice object or null * @return string Field value */ private function getFieldValue(array $field, $invoice = null): string { $name = $field['name'] ?? ''; $default_value = $field['default_value'] ?? $field['value'] ?? ''; // Handle callable default values if (is_callable($default_value)) { $default_value = $default_value(); } // Allow Pro plugins to populate field values from meta data $field = apply_filters('easy_invoice_populate_field_values', $field, $invoice); if (is_array($invoice)) { // Handle different array structures if (isset($invoice[$name])) { $value = $invoice[$name]; } elseif (isset($invoice['default_values'][$name])) { $value = $invoice['default_values'][$name]; } else { $value = $default_value; } } else { if ($invoice) { // First check if the field has a populated value from the hook if (isset($field['value']) && $field['value'] !== null && $field['value'] !== '') { $value = $field['value']; } else { // Use dynamic property access (magic __get method) if (method_exists($invoice, '__get') || property_exists($invoice, $name)) { $value = $invoice->$name; } else { // Fallback to dynamic getter method $getter_method = 'get' . easy_invoice_str_replace(' ', '', ucwords(easy_invoice_str_replace(['-', '_'], ' ', $name))); if (method_exists($invoice, $getter_method)) { $value = $invoice->$getter_method(); } else { $value = $default_value; } } // Special handling for currency fields - use raw values for form display if ($name === 'currency_code') { if (method_exists($invoice, 'getRawCurrencyCode')) { return $invoice->getRawCurrencyCode(); } return $value ?? 'global'; } if ($name === 'currency_position') { if (method_exists($invoice, 'getRawCurrencyPosition')) { return $invoice->getRawCurrencyPosition(); } return $value ?? 'global'; } // Special handling for payment_gateways field if ($name === 'payment_gateways') { if (is_array($value)) { return implode(',', $value); } return (string) $value; } if (empty($value) && $value !== '0') { $value = $default_value; } } } else { $value = $default_value; } } return (string) ($value ?? ''); } }