$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(
'',
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(
'',
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(
'',
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(
'',
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(
'',
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(
'',
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(
'%s ',
esc_attr($option_value),
$selected,
esc_html($option_label)
);
}
return sprintf(
'',
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(
'',
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(
'',
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(
'',
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 .= '' . __('Choose specific payment methods', 'easy-invoice') . ' ';
$gateways_html .= '';
$gateways_html .= ' ';
$gateways_html .= ' ';
$gateways_html .= '
';
$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 .= '';
foreach ($enabled_gateways as $gateway_id => $gateway) {
$checked = in_array($gateway_id, $selected_gateways) ? 'checked' : '';
$is_checked = in_array($gateway_id, $selected_gateways);
$gateway_title = $gateway->getTitle();
$gateway_description = $gateway->getDescription();
$is_available = $gateway->isAvailable();
$availability_badge = $is_available ? '' : '
' . __('Configuration required', 'easy-invoice') . ' ';
$card_classes = 'gateway-card';
if ($is_checked) {
$card_classes .= ' checked';
}
if (!$is_available) {
$card_classes .= ' opacity-60';
}
$gateways_html .= sprintf(
'
'
. ' '
. ' ' .
''
. '%s '
. '%s'
. '%s '
. '
' .
' ',
esc_attr($card_classes),
esc_attr($id),
esc_attr($gateway_id),
esc_attr($name),
esc_attr($gateway_id),
$checked,
esc_html($gateway_title),
$availability_badge,
esc_html($gateway_description)
);
}
$gateways_html .= '
';
// Add JavaScript to handle toggle and card clicks
$gateways_html .= '';
}
return sprintf(
'',
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 ?? '');
}
}