config_cache = null; // Also clear any WordPress object cache wp_cache_delete('easy_invoice_settings_config', 'easy_invoice'); // Force clear any other caches if (function_exists('wp_cache_flush')) { wp_cache_flush(); } } /** * Initialize the controller * * @return void */ public function init() { // Add AJAX handlers add_action('wp_ajax_easy_invoice_save_settings', [$this, 'saveSettings']); add_action('wp_ajax_easy_invoice_test_email', [$this, 'testEmail']); add_action('wp_ajax_easy_invoice_test_template_email', [$this, 'testTemplateEmail']); add_action('wp_ajax_easy_invoice_test_payment_reminder_email', [$this, 'testPaymentReminderEmail']); add_action('wp_ajax_regenerate_invoice_numbers', [$this, 'ajaxRegenerateInvoiceNumbers']); add_action('wp_ajax_regenerate_quote_numbers', [$this, 'ajaxRegenerateQuoteNumbers']); // Clear cache on admin init to ensure new fields are recognized add_action('admin_init', [$this, 'clearCache']); // Enqueue admin scripts add_action('admin_enqueue_scripts', [$this, 'enqueueAdminScripts']); // Initialize settings $this->initializeSettings(); } /** * Enqueue admin scripts and styles for the settings page. * * @param string $hook_suffix The current admin page. * @return void */ public function enqueueAdminScripts($hook_suffix) { // Check if we are on the Easy Invoice settings page. if (empty($hook_suffix) || strpos($hook_suffix, PagesSlugs::SETTINGS) === false) { return; } wp_enqueue_script('jquery-ui-sortable'); wp_enqueue_media(); // For the logo uploader // Enqueue Select2 for enhancing multiselect fields wp_enqueue_style( 'select2', 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css', [], '4.0.13' ); wp_enqueue_script( 'select2', 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js', ['jquery'], '4.0.13', true ); // Enqueue confirmation modal for premium features wp_enqueue_script( 'easy-invoice-confirmation-modal', EASY_INVOICE_URL . 'assets/js/confirmation-modal.js', ['jquery'], EASY_INVOICE_VERSION, true ); // Enqueue toast notification system wp_enqueue_script( 'easy-invoice-toast', EASY_INVOICE_URL . 'assets/js/easy-invoice-toast.js', ['jquery'], EASY_INVOICE_VERSION, true ); $script_handle = 'easy-invoice-settings'; wp_enqueue_script( $script_handle, EASY_INVOICE_URL . 'assets/js/settings.js', ['jquery', 'jquery-ui-sortable', 'wp-util', 'select2', 'easy-invoice-confirmation-modal', 'media-views'], EASY_INVOICE_VERSION, true ); // Enqueue the new settings.css only on the settings page wp_enqueue_style( 'easy-invoice-settings', EASY_INVOICE_URL . 'assets/css/settings.css', [], EASY_INVOICE_VERSION ); $localize_data = apply_filters('easy_invoice_settings_js_data', [ 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('easy_invoice_settings'), 'saveSuccess' => __('Settings saved successfully', 'easy-invoice'), 'saveError' => __('Error saving settings', 'easy-invoice'), ]); wp_localize_script($script_handle, 'easyInvoiceSettings', $localize_data); do_action('easy_invoice_after_admin_scripts', $hook_suffix); } /** * Check if Easy Invoice Pro is active * * @return bool */ private function isProActive(): bool { return easy_invoice_has_pro(); } /** * Get settings fields configuration * * @return array */ public function get_settings_fields_config() { // Use cached config if available if (is_array($this->config_cache)) { return $this->config_cache; } $config = [ 'company' => [ 'title' => __('Company Information', 'easy-invoice'), 'description' => __('Set up your company details', 'easy-invoice'), 'icon' => 'fas fa-building', 'fields' => [ 'easy_invoice_company_name' => ['label' => __('Company Name', 'easy-invoice'), 'type' => 'text', 'default' => '', 'col_span' => 'sm:col-span-6' ], 'easy_invoice_company_email' => ['label' => __('Email', 'easy-invoice'), 'type' => 'email', 'default' => '', 'col_span' => 'sm:col-span-6' ], 'easy_invoice_company_phone' => ['label' => __('Phone Number', 'easy-invoice'), 'type' => 'tel', 'default' => '', 'col_span' => 'sm:col-span-6' ], 'easy_invoice_company_website' => ['label' => __('Website', 'easy-invoice'), 'type' => 'url', 'default' => '', 'col_span' => 'sm:col-span-6' ], 'easy_invoice_company_address' => ['label' => __('Address', 'easy-invoice'), 'type' => 'textarea', 'default' => '', 'col_span' => 'sm:col-span-6' ], 'easy_invoice_tax_number' => ['label' => __('Tax ID / VAT Number', 'easy-invoice'), 'type' => 'text', 'default' => '', 'col_span' => 'sm:col-span-6' ], 'easy_invoice_company_logo' => ['label' => __('Company Logo', 'easy-invoice'), 'type' => 'image', 'default' => '', 'col_span' => 'sm:col-span-6' ], ] ], 'invoice' => [ 'title' => __('Invoice Settings', 'easy-invoice'), 'description' => __('Configure invoice-specific settings and preferences', 'easy-invoice'), 'icon' => 'fas fa-file-invoice', 'fields' => [ 'easy_invoice_invoice_prefix' => [ 'label' => __('Invoice Prefix', 'easy-invoice'), 'type' => 'text', 'default' => 'EIIN_', 'description' => __('Prefix for invoice numbers (e.g., EIIN_, INV-)', 'easy-invoice'), 'col_span' => 'sm:col-span-2' ], 'easy_invoice_next_invoice_number' => [ 'label' => __('Next Invoice Number', 'easy-invoice'), 'type' => 'number', 'default' => '1', 'description' => __('Set the next invoice number to be generated. This will be the number of the next invoice created.', 'easy-invoice'), 'col_span' => 'sm:col-span-2', ], 'easy_invoice_regenerate_invoice_numbers' => [ 'label' => __('Regenerate Invoice Numbers', 'easy-invoice'), 'type' => 'button', 'button_text' => __('Regenerate All Invoice Numbers', 'easy-invoice'), 'button_class' => 'button button-secondary', 'description' => __('Click to regenerate all invoice numbers starting from the Last Invoice Number. This will update all existing invoices with new sequential numbers.', 'easy-invoice'), 'col_span' => 'sm:col-span-2', 'ajax_action' => 'regenerate_invoice_numbers' ], 'easy_invoice_invoice_show_adjust_field' => [ 'label' => __('Show/Hide Adjust Field', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'yes', 'description' => __('Enable/Disable Adjust field. Tick this to show adjust field', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_invoice_terms_conditions' => [ 'label' => __('Terms & Conditions', 'easy-invoice'), 'type' => 'wp_editor', 'default' => __('Payment is due within 30 days from date of invoice', 'easy-invoice'), 'description' => __('Terms and conditions that will be displayed on your invoice', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_invoice_footer_text' => [ 'label' => __('Footer Text', 'easy-invoice'), 'type' => 'wp_editor', 'default' => '', 'description' => __('You can modify your invoice footer text from here. HTML tags supports: a, br, em, strong, hr, p, h1 to h4', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], ], ], 'quote' => [ 'title' => __('Quote Settings', 'easy-invoice'), 'description' => __('Configure quote-specific settings and preferences', 'easy-invoice'), 'icon' => 'fas fa-file-contract', 'fields' => [ 'easy_invoice_quote_prefix' => [ 'label' => __('Quote Prefix', 'easy-invoice'), 'type' => 'text', 'default' => 'EIQN_', 'description' => __('Prefix for quote numbers (e.g., EIQN_, QT-)', 'easy-invoice'), 'col_span' => 'sm:col-span-2' ], 'easy_invoice_next_quote_number' => [ 'label' => __('Next Quote Number', 'easy-invoice'), 'type' => 'number', 'default' => '1', 'description' => __('Set the next quote number to be generated. This will be the number of the next quote created.', 'easy-invoice'), 'col_span' => 'sm:col-span-2', ], 'easy_invoice_regenerate_quote_numbers' => [ 'label' => __('Regenerate Quote Numbers', 'easy-invoice'), 'type' => 'button', 'button_text' => __('Regenerate All Quote Numbers', 'easy-invoice'), 'button_class' => 'button button-secondary', 'description' => __('Click to regenerate all quote numbers starting from the Next Quote Number. This will update all existing quotes with new sequential numbers.', 'easy-invoice'), 'col_span' => 'sm:col-span-2', 'ajax_action' => 'regenerate_quote_numbers' ], 'easy_invoice_quote_show_adjust_field' => [ 'label' => __('Show/Hide Adjust Field', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'yes', 'description' => __('Enable/Disable Adjust field. Tick this to show adjust field', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_quote_terms_conditions' => [ 'label' => __('Terms & Conditions', 'easy-invoice'), 'type' => 'wp_editor', 'default' => __('This quote has a fixed price. Upon acceptance, we kindly ask for a 25% deposit prior to initiating the work.', 'easy-invoice'), 'description' => __('Terms and conditions that will be displayed on your quote!', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_quote_footer_text' => [ 'label' => __('Footer Text', 'easy-invoice'), 'type' => 'wp_editor', 'default' => __('Thanks for choosing Easy Invoice', 'easy-invoice'), 'description' => __('You can modify your quote footer text from here. HTML tags supports: a, br, em, strong, hr, p, h1 to h4', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_quote_accept_button' => [ 'label' => __('Accept quote button', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'yes', 'description' => __('Show/hide accept quote button on quotes.', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_quote_accept_action' => [ 'label' => __('Accept quote button action', 'easy-invoice'), 'type' => 'select', 'default' => 'convert', 'options' => [ 'convert' => __('Convert quote to invoice - Draft', 'easy-invoice'), 'convert_available' => __('Convert quote to invoice - Available', 'easy-invoice'), 'convert_send' => __('Convert quote to invoice and send to client - Available', 'easy-invoice'), 'duplicate' => __('Create new invoice, keep quote as-is - Draft', 'easy-invoice'), 'duplicate_send' => __('Create new invoice and send to client, keep quote as-is - Available', 'easy-invoice'), 'do_nothing' => __('Do nothing', 'easy-invoice'), ], 'description' => __('Upon the client clicking the "accept quote" button, the subsequent action will be activated.', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_quote_accept_text' => [ 'label' => __('Accept Quote Text', 'easy-invoice'), 'type' => 'wp_editor', 'default' => __('Important: When you accept this Quote, an Invoice will be created automatically. This will form a legally binding contract.', 'easy-invoice'), 'description' => __('This information tells your client what happens once they accept the Quote', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_quote_accepted_message' => [ 'label' => __('Accepted Quote Message', 'easy-invoice'), 'type' => 'wp_editor', 'default' => __('You\'ve confirmed the Quote.
We\'ll get in touch with you shortly.', 'easy-invoice'), 'description' => __('If the client accepts the Quote, display this message.', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_quote_decline_reason_required' => [ 'label' => __('Decline Reason Required', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'no', 'description' => __('Make the \'Reason for declining\' field mandatory when rejecting.', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_quote_declined_message' => [ 'label' => __('Declined Quote Message', 'easy-invoice'), 'type' => 'wp_editor', 'default' => '', 'description' => __('Message to display if client declines the Quote', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], ], ], 'currency' => [ 'title' => __('Currency Settings', 'easy-invoice'), 'description' => __('Configure currency display preferences', 'easy-invoice'), 'icon' => 'fas fa-dollar-sign', 'fields' => [ 'easy_invoice_currency_code' => [ 'label' => __('Currency & Symbol', 'easy-invoice'), 'type' => 'select', 'default' => 'USD', 'options' => CurrencyHelper::getCurrencyOptions(), 'col_span' => 'sm:col-span-6', 'description' => __('Select your preferred currency. The symbol will be automatically set.', 'easy-invoice') ], 'easy_invoice_currency_position' => [ 'label' => __('Symbol Position', 'easy-invoice'), 'type' => 'select', 'default' => 'left', 'options' => [ 'left' => __('Left', 'easy-invoice'), 'right' => __('Right', 'easy-invoice'), 'left_space' => __('Left with space', 'easy-invoice'), 'right_space' => __('Right with space', 'easy-invoice'), ], 'col_span' => 'sm:col-span-3' ], 'easy_invoice_currency_symbol_type' => [ 'label' => __('Currency Symbol Type', 'easy-invoice'), 'type' => 'select', 'default' => 'symbol', 'options' => [ 'code' => __('Currency Code', 'easy-invoice'), 'symbol' => __('Currency Symbol', 'easy-invoice'), ], 'description' => __('Choose whether to display currency code (USD) or currency symbol ($)', 'easy-invoice'), 'col_span' => 'sm:col-span-3' ], 'easy_invoice_thousands_separator' => ['label' => __('Thousands Separator', 'easy-invoice'), 'type' => 'text', 'default' => ',', 'col_span' => 'sm:col-span-3' ], 'easy_invoice_decimal_separator' => ['label' => __('Decimal Separator', 'easy-invoice'), 'type' => 'text', 'default' => '.', 'col_span' => 'sm:col-span-3' ], 'easy_invoice_decimal_precision' => ['label' => __('Decimal Places', 'easy-invoice'), 'type' => 'number', 'default' => '2', 'min' => 0, 'max' => 4, 'col_span' => 'sm:col-span-3' ], ] ], 'tax' => [ 'title' => __('Tax Settings', 'easy-invoice'), 'description' => __('Configure tax rates and preferences', 'easy-invoice'), 'icon' => 'fas fa-percent', 'fields' => [ 'easy_invoice_tax_enabled' => ['label' => __('Enable Tax', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'no', 'col_span' => 'sm:col-span-6' ], 'easy_invoice_tax_entry_method' => [ 'label' => __('How do you enter tax?', 'easy-invoice'), 'type' => 'select', 'default' => 'exclusive', 'options' => [ 'inclusive' => __('I will enter price inclusive of tax', 'easy-invoice'), 'exclusive' => __('I will enter price exclusive of tax', 'easy-invoice'), ], 'description' => __('Choose how you want to enter prices - with or without tax included', 'easy-invoice'), 'col_span' => 'sm:col-span-6' ], 'easy_invoice_tax_rate' => ['label' => __('Default Tax Rate (%)', 'easy-invoice'), 'type' => 'number', 'default' => '0', 'step' => '0.01', 'min' => '0', 'max' => '100', 'col_span' => 'sm:col-span-3' ], 'easy_invoice_tax_name' => ['label' => __('Tax Name', 'easy-invoice'), 'type' => 'text', 'default' => __('Tax', 'easy-invoice'), 'col_span' => 'sm:col-span-3' ], ] ], 'payment' => [ 'title' => __('Payment Methods', 'easy-invoice'), 'description' => __('Configure and order available payment methods.', 'easy-invoice'), 'icon' => 'fas fa-credit-card', 'is_special_section' => true, 'gateways' => $this->getGatewaySettingsConfigs(), ], 'email' => [ 'title' => __('Email Settings', 'easy-invoice'), 'description' => __('Configure email sending options and templates', 'easy-invoice'), 'icon' => 'fas fa-envelope', 'subsections' => [ 'general' => [ 'title' => __('General Email Settings', 'easy-invoice'), 'description' => __('Configure general email sending options', 'easy-invoice'), 'fields' => [ 'easy_invoice_email_from_name' => ['label' => __('From Name', 'easy-invoice'), 'type' => 'text', 'default' => get_bloginfo('name') ?: 'Easy Invoice', 'col_span' => 'sm:col-span-3'], 'easy_invoice_email_from_address' => ['label' => __('From Email Address', 'easy-invoice'), 'type' => 'email', 'default' => get_bloginfo('admin_email') ?: get_option('admin_email', ''), 'col_span' => 'sm:col-span-3'], 'easy_invoice_email_reply_to' => ['label' => __('Reply-To Email', 'easy-invoice'), 'type' => 'email', 'default' => '', 'col_span' => 'sm:col-span-3'], 'easy_invoice_email_reply_to_name' => ['label' => __('Reply-To Name', 'easy-invoice'), 'type' => 'text', 'default' => '', 'col_span' => 'sm:col-span-3'], 'easy_invoice_enable_email_styling' => ['label' => __('Enable HTML Emails', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'yes', 'col_span' => 'sm:col-span-6'], 'easy_invoice_bcc_admin' => ['label' => __('BCC Admin on All Emails', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'no', 'col_span' => 'sm:col-span-6'], 'easy_invoice_admin_email' => ['label' => __('Admin Email for BCC', 'easy-invoice'), 'type' => 'email', 'default' => get_option('admin_email', ''), 'col_span' => 'sm:col-span-6'], 'easy_invoice_email_logo' => ['label' => __('Email Logo URL', 'easy-invoice'), 'type' => 'url', 'default' => '', 'col_span' => 'sm:col-span-6'], 'easy_invoice_email_footer_text' => ['label' => __('Email Footer Text', 'easy-invoice'), 'type' => 'textarea', 'default' => '', 'col_span' => 'sm:col-span-6'], 'easy_invoice_test_email' => [ 'label' => __('Test Email', 'easy-invoice'), 'type' => 'test_email', 'default' => '', 'col_span' => 'sm:col-span-6', 'description' => __('Send a test email to verify your email configuration is working correctly.', 'easy-invoice') ], ] ], 'invoice_available' => [ 'title' => __('Invoice Available Email', 'easy-invoice'), 'description' => __('Configure email sent when an invoice is available for the client', 'easy-invoice'), 'fields' => [ 'easy_invoice_invoice_email_enabled' => ['label' => __('Enable Invoice Available Email', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'yes', 'col_span' => 'sm:col-span-6'], 'easy_invoice_invoice_email_subject' => ['label' => __('Subject', 'easy-invoice'), 'type' => 'text', 'default' => __('Your Invoice #{{invoice_number}} from {{company_name}}', 'easy-invoice'), 'col_span' => 'sm:col-span-6'], 'easy_invoice_invoice_email_body' => ['label' => __('Email Body', 'easy-invoice'), 'type' => 'wp_editor', 'default' => __('

📄 Your Invoice is Ready

Dear {{client_name}},

Invoice #{{invoice_number}}
{{total_amount}}
Due Date: {{due_date}}

Your invoice has been prepared and is ready for payment. You can view and download the complete invoice from the attachment.

📋 Payment Details:
• Invoice Number: {{invoice_number}}
• Total Amount: {{total_amount}}
• Due Date: {{due_date}}
• Payment Terms: {{payment_terms}}

⚠️ Important: Please ensure payment is received by the due date to avoid any late fees or service interruptions.

If you have any questions about this invoice, please don\'t hesitate to contact us.

Thank you for your business!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice'), 'col_span' => 'sm:col-span-6'], 'easy_invoice_invoice_test_template' => [ 'label' => __('Test Invoice Email', 'easy-invoice'), 'type' => 'test_template_email', 'default' => '', 'col_span' => 'sm:col-span-6', 'description' => __('Send a test invoice email to verify the template and configuration.', 'easy-invoice'), 'template_type' => 'invoice_available' ], ] ], 'quote_available' => [ 'title' => __('Quote Available Email', 'easy-invoice'), 'description' => __('Configure email sent when a quote is available for the client', 'easy-invoice'), 'fields' => [ 'easy_invoice_quote_email_enabled' => ['label' => __('Enable Quote Available Email', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'yes', 'col_span' => 'sm:col-span-6'], 'easy_invoice_quote_email_subject' => ['label' => __('Subject', 'easy-invoice'), 'type' => 'text', 'default' => __('Your Quote #{{quote_number}} from {{company_name}}', 'easy-invoice'), 'col_span' => 'sm:col-span-6'], 'easy_invoice_quote_email_body' => ['label' => __('Email Body', 'easy-invoice'), 'type' => 'wp_editor', 'default' => __('

📋 Your Quote is Ready

Dear {{client_name}},

Quote #{{quote_number}}
{{total_amount}}
Valid Until: {{expiry_date}}

We have prepared a detailed quote for your project. You can view and download the complete quote from the attachment or visit the link below.

📋 Quote Summary:
• Quote Number: {{quote_number}}
• Total Amount: {{total_amount}}
• Valid Until: {{expiry_date}}
• Terms: {{payment_terms}}

🔗 View Quote Online:
{{quote_url}}

Shortcode: [easy_quote_url number="{{quote_number}}" text="View Quote"]

⏰ Time Sensitive: This quote is valid until {{expiry_date}}. Please review and respond within this timeframe.

If you have any questions or would like to discuss any aspects of this quote, please contact us.

We look forward to working with you!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice'), 'col_span' => 'sm:col-span-6'], 'easy_invoice_quote_test_template' => [ 'label' => __('Test Quote Email', 'easy-invoice'), 'type' => 'test_template_email', 'default' => '', 'col_span' => 'sm:col-span-6', 'description' => __('Send a test quote email to verify the template and configuration.', 'easy-invoice'), 'template_type' => 'quote_available' ], ] ], 'payment_received' => [ 'title' => __('Payment Received Email', 'easy-invoice'), 'description' => __('Configure email sent when a payment is received', 'easy-invoice'), 'fields' => [ 'easy_invoice_payment_email_enabled' => ['label' => __('Enable Payment Received Email', 'easy-invoice'), 'type' => 'checkbox', 'default' => 'yes', 'col_span' => 'sm:col-span-6'], 'easy_invoice_payment_email_subject' => ['label' => __('Subject', 'easy-invoice'), 'type' => 'text', 'default' => __('Payment Received - Invoice #{{invoice_number}}', 'easy-invoice'), 'col_span' => 'sm:col-span-6'], 'easy_invoice_payment_email_body' => ['label' => __('Email Body', 'easy-invoice'), 'type' => 'wp_editor', 'default' => __('

✅ Payment Received - Thank You!

Dear {{client_name}},

Payment Confirmation
Invoice #{{invoice_number}}
{{payment_amount}}
Payment Date: {{payment_date}}
Payment Method: {{payment_method}}

We have successfully received your payment. Thank you for your prompt payment!

📊 Payment Details:
• Invoice Number: {{invoice_number}}
• Amount Paid: {{payment_amount}}
• Payment Date: {{payment_date}}
• Payment Method: {{payment_method}}
• Transaction ID: {{transaction_id}}

🎉 Status: PAID
Your payment has been processed and your account is now up to date. We appreciate your business!

If you have any questions about this payment or need a receipt, please don\'t hesitate to contact us.

Thank you for choosing our services!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice'), 'col_span' => 'sm:col-span-6'], 'easy_invoice_payment_test_template' => [ 'label' => __('Test Payment Email', 'easy-invoice'), 'type' => 'test_template_email', 'default' => '', 'col_span' => 'sm:col-span-6', 'description' => __('Send a test payment email to verify the template and configuration.', 'easy-invoice'), 'template_type' => 'payment_received' ], ] ], ] ], 'text_settings' => [ 'title' => __('Text Settings', 'easy-invoice'), 'description' => __('Customize text labels for invoices and quotes. Perfect for multi-language support.', 'easy-invoice'), 'icon' => ' ', 'fields' => [ // Invoice Text Settings 'easy_invoice_text_invoice' => ['label' => __('Invoice', 'easy-invoice'), 'type' => 'text', 'default' => __('Invoice', 'easy-invoice'), 'col_span' => '', 'description' => __('Label for single invoice', 'easy-invoice')], 'easy_invoice_text_invoices' => ['label' => __('Invoices', 'easy-invoice'), 'type' => 'text', 'default' => __('Invoices', 'easy-invoice'), 'col_span' => '', 'description' => __('Label for multiple invoices', 'easy-invoice')], 'easy_invoice_text_to' => ['label' => __('To', 'easy-invoice'), 'type' => 'text', 'default' => __('To', 'easy-invoice'), 'col_span' => '', 'description' => __('To label on invoice/quote', 'easy-invoice')], 'easy_invoice_text_invoice_number' => ['label' => __('Invoice Number', 'easy-invoice'), 'type' => 'text', 'default' => __('Invoice Number', 'easy-invoice'), 'col_span' => '', 'description' => __('Invoice number label', 'easy-invoice')], 'easy_invoice_text_invoice_date' => ['label' => __('Invoice Date', 'easy-invoice'), 'type' => 'text', 'default' => __('Invoice Date', 'easy-invoice'), 'col_span' => '', 'description' => __('Invoice date label', 'easy-invoice')], 'easy_invoice_text_due_date' => ['label' => __('Due Date', 'easy-invoice'), 'type' => 'text', 'default' => __('Due Date', 'easy-invoice'), 'col_span' => '', 'description' => __('Due date label', 'easy-invoice')], 'easy_invoice_text_total_due' => ['label' => __('Total Due', 'easy-invoice'), 'type' => 'text', 'default' => __('Total Due', 'easy-invoice'), 'col_span' => '', 'description' => __('Total due label', 'easy-invoice')], 'easy_invoice_text_qty' => ['label' => __('Qty', 'easy-invoice'), 'type' => 'text', 'default' => __('Qty', 'easy-invoice'), 'col_span' => '', 'description' => __('Quantity label', 'easy-invoice')], 'easy_invoice_text_service' => ['label' => __('Service', 'easy-invoice'), 'type' => 'text', 'default' => __('Service', 'easy-invoice'), 'col_span' => '', 'description' => __('Service label', 'easy-invoice')], 'easy_invoice_text_rate_price' => ['label' => __('Rate', 'easy-invoice'), 'type' => 'text', 'default' => __('Rate', 'easy-invoice'), 'col_span' => '', 'description' => __('Rate or price label', 'easy-invoice')], 'easy_invoice_text_adjust' => ['label' => __('Adjust', 'easy-invoice'), 'type' => 'text', 'default' => __('Adjust', 'easy-invoice'), 'col_span' => '', 'description' => __('Adjust label', 'easy-invoice')], 'easy_invoice_text_sub_total' => ['label' => __('Sub Total', 'easy-invoice'), 'type' => 'text', 'default' => __('Sub Total', 'easy-invoice'), 'col_span' => '', 'description' => __('Sub total label', 'easy-invoice')], 'easy_invoice_text_total' => ['label' => __('Total', 'easy-invoice'), 'type' => 'text', 'default' => __('Total', 'easy-invoice'), 'col_span' => '', 'description' => __('Total label', 'easy-invoice')], 'easy_invoice_text_tax' => ['label' => __('Tax', 'easy-invoice'), 'type' => 'text', 'default' => __('Tax', 'easy-invoice'), 'col_span' => '', 'description' => __('Tax label', 'easy-invoice')], 'easy_invoice_text_discount' => ['label' => __('Discount', 'easy-invoice'), 'type' => 'text', 'default' => __('Discount', 'easy-invoice'), 'col_span' => '', 'description' => __('Discount label', 'easy-invoice')], 'easy_invoice_text_print' => ['label' => __('Print', 'easy-invoice'), 'type' => 'text', 'default' => __('Print', 'easy-invoice'), 'col_span' => '', 'description' => __('Print button text', 'easy-invoice')], 'easy_invoice_text_download_pdf' => ['label' => __('Download as PDF', 'easy-invoice'), 'type' => 'text', 'default' => __('Download as PDF', 'easy-invoice'), 'col_span' => '', 'description' => __('Download PDF button text', 'easy-invoice')], 'easy_invoice_text_send_email' => ['label' => __('Send Email', 'easy-invoice'), 'type' => 'text', 'default' => __('Send Email', 'easy-invoice'), 'col_span' => '', 'description' => __('Send email button text', 'easy-invoice')], 'easy_invoice_text_pay_now' => ['label' => __('Pay Now', 'easy-invoice'), 'type' => 'text', 'default' => __('Pay Now', 'easy-invoice'), 'col_span' => '', 'description' => __('Pay now button text', 'easy-invoice')], // Quote Text Settings 'easy_invoice_text_quote' => ['label' => __('Quote', 'easy-invoice'), 'type' => 'text', 'default' => __('Quote', 'easy-invoice'), 'col_span' => '', 'description' => __('Label for single quote', 'easy-invoice')], 'easy_invoice_text_quote_number' => ['label' => __('Quote Number', 'easy-invoice'), 'type' => 'text', 'default' => __('Quote Number', 'easy-invoice'), 'col_span' => '', 'description' => __('Quote number label', 'easy-invoice')], 'easy_invoice_text_accept_quote' => ['label' => __('Accept Quote', 'easy-invoice'), 'type' => 'text', 'default' => __('Accept Quote', 'easy-invoice'), 'col_span' => '', 'description' => __('Accept quote button text', 'easy-invoice')], 'easy_invoice_text_decline_quote' => ['label' => __('Decline Quote', 'easy-invoice'), 'type' => 'text', 'default' => __('Decline Quote', 'easy-invoice'), 'col_span' => '', 'description' => __('Decline quote button text', 'easy-invoice')], 'easy_invoice_text_decline_reason' => ['label' => __('Reason for declining', 'easy-invoice'), 'type' => 'text', 'default' => __('Reason for declining', 'easy-invoice'), 'col_span' => '', 'description' => __('Decline reason label', 'easy-invoice')], 'easy_invoice_text_valid_until' => ['label' => __('Valid Until Date', 'easy-invoice'), 'type' => 'text', 'default' => __('Valid Until Date', 'easy-invoice'), 'col_span' => '', 'description' => __('Valid until date label', 'easy-invoice')], 'easy_invoice_text_quote_date' => ['label' => __('Quote Date', 'easy-invoice'), 'type' => 'text', 'default' => __('Quote Date', 'easy-invoice'), 'col_span' => '', 'description' => __('Quote date label', 'easy-invoice')], ] ], 'advanced' => [ 'title' => __('Advanced Settings', 'easy-invoice'), 'description' => __('Configure system preferences', 'easy-invoice'), 'icon' => 'fas fa-cog', 'fields' => [ 'easy_invoice_date_format' => [ 'label' => __('Date Format', 'easy-invoice'), 'type' => 'select', 'default' => 'us', 'options' => [ 'us' => __('MM/DD/YYYY (US) - 01/15/2024', 'easy-invoice'), 'uk' => __('DD/MM/YYYY (UK) - 15/01/2024', 'easy-invoice'), 'iso' => __('YYYY-MM-DD (ISO) - 2024-01-15', 'easy-invoice'), ], 'col_span' => 'sm:col-span-3' ], 'easy_invoice_invoice_numbering' => ['label' => __('Auto-increment invoice numbers', 'easy-invoice'), 'type' => 'checkbox', 'description' => __('Automatically increment invoice numbers for new invoices', 'easy-invoice'), 'default' => 'yes', 'col_span' => 'sm:col-span-6' ], 'easy_invoice_payment_reminder_days' => ['label' => __('Payment Reminder Days', 'easy-invoice'), 'type' => 'number', 'default' => 3, 'col_span' => 'sm:col-span-3'], ] ], ]; // Cache and filter the config $this->config_cache = apply_filters('easy_invoice_settings_fields_config', $config); return $this->config_cache; } /** * Get all gateway settings configurations * * @return array Gateway settings configs */ private function getGatewaySettingsConfigs(): array { $gateway_configs = []; try { // Get gateway manager from the main plugin instance $gateway_manager = \EasyInvoice\EasyInvoice::getInstance()->getGatewayManager(); $gateways = $gateway_manager->getGateways(); // Collect settings from each gateway foreach ($gateways as $gateway_id => $gateway) { try { $gateway_configs[$gateway_id] = $gateway->getSettingsConfig(); } catch (\Exception $e) { // Log the error but continue with other gateways $gateway_configs[$gateway_id] = []; } } } catch (\Exception $e) { } return $gateway_configs; } /** * Prepare settings for display with proper filtering * * @param array $settings The settings array * @return array The filtered settings */ public function prepareSettingsForDisplay($settings) { return apply_filters('easy_invoice_settings_for_display', $settings); } /** * Display method implementation * * @param array $args Display arguments * @return void */ public function display(array $args = []) { $page = isset($args['page']) ? $args['page'] : ''; $subsection = isset($args['subsection']) ? $args['subsection'] : ''; // Clear cache to ensure new fields are recognized $this->clearCache(); switch ($page) { case PagesSlugs::SETTINGS: if (!empty($subsection)) { // Handle email settings subsections $this->displayEmailSettingsPage($subsection); } else { $this->displaySettingsPage(); } break; default: $this->displaySettingsPage(); break; } } /** * Display email settings page for specific subsection * * @param string $subsection The subsection to display * @return void */ protected function displayEmailSettingsPage($subsection) { // Get settings configuration $settings_config = $this->get_settings_fields_config(); $settings = $this->getSettings(); // Filter to show only email settings $email_config = $settings_config['email'] ?? []; // Map subsection to the appropriate subsection in email config $subsection_mapping = [ PagesSlugs::EMAIL_SETTINGS_GENERAL => 'general', PagesSlugs::EMAIL_SETTINGS_INVOICE => 'invoice_available', PagesSlugs::EMAIL_SETTINGS_QUOTE => 'quote_available', PagesSlugs::EMAIL_SETTINGS_PAYMENT => 'payment_received', PagesSlugs::EMAIL_SETTINGS_PAYMENT_REMINDER => 'payment_reminder', ]; $target_subsection = $subsection_mapping[$subsection] ?? 'general'; // Create a modified config with only the target subsection $filtered_config = [ 'email' => [ 'title' => __('Email Settings', 'easy-invoice'), 'description' => __('Configure email sending options and templates', 'easy-invoice'), 'icon' => 'fas fa-envelope', 'subsections' => [ $target_subsection => $email_config['subsections'][$target_subsection] ?? [] ] ] ]; // Include the settings page template with filtered config include EASY_INVOICE_PLUGIN_DIR . 'templates/settings-page.php'; } /** * Display settings page * * @return void */ protected function displaySettingsPage() { $settings = $this->getSettings(); // Allow developers to modify settings before display $settings = apply_filters('easy_invoice_before_display_settings', $settings); // Ensure payment methods are set (this is critical for gateway checkboxes) if (!isset($settings['easy_invoice_payment_methods']) || !is_array($settings['easy_invoice_payment_methods'])) { $settings['easy_invoice_payment_methods'] = get_option('easy_invoice_payment_methods', []); } // Ensure gateway order is set if (!isset($settings['easy_invoice_payment_gateway_order']) || !is_array($settings['easy_invoice_payment_gateway_order'])) { $settings['easy_invoice_payment_gateway_order'] = get_option('easy_invoice_payment_gateway_order', []); } $gateway_manager = \EasyInvoice\EasyInvoice::getInstance()->getGatewayManager(); $all_gateways_unsorted = $gateway_manager->getGateways(); $gateway_order_option = $settings['easy_invoice_payment_gateway_order']; $payment_methods_enabled = $settings['easy_invoice_payment_methods']; $all_gateways_sorted = []; if (!empty($gateway_order_option)) { foreach ($gateway_order_option as $gateway_id) { if (isset($all_gateways_unsorted[$gateway_id])) { $all_gateways_sorted[$gateway_id] = $all_gateways_unsorted[$gateway_id]; unset($all_gateways_unsorted[$gateway_id]); } } } $all_gateways_sorted = array_merge($all_gateways_sorted, $all_gateways_unsorted); $settings_config = $this->get_settings_fields_config(); // Prepare template variables $template_args = apply_filters('easy_invoice_settings_template_args', [ 'settings' => $settings, 'settings_config' => $settings_config, 'all_gateways_sorted' => $all_gateways_sorted, 'payment_methods_enabled' => $payment_methods_enabled ]); // Display the template with template args $this->displayTemplate( apply_filters('easy_invoice_settings_template_path', EASY_INVOICE_PLUGIN_DIR . 'templates/settings-page.php'), $template_args ); // Action for plugins to add their own content after the settings page do_action('easy_invoice_after_settings_page'); } /** * Save payment settings * * @param array $posted_settings Posted settings * @param array $response Response array * @return void */ private function savePaymentSettings($posted_settings, &$response) { // Handle payment methods if (isset($posted_settings['easy_invoice_payment_methods']) && is_array($posted_settings['easy_invoice_payment_methods'])) { $sanitized_methods = array_map('sanitize_key', $posted_settings['easy_invoice_payment_methods']); update_option('easy_invoice_payment_methods', $sanitized_methods); $response['saved_options']['easy_invoice_payment_methods'] = $sanitized_methods; } else { update_option('easy_invoice_payment_methods', []); $response['saved_options']['easy_invoice_payment_methods'] = []; } // Handle gateway order if (isset($posted_settings['easy_invoice_gateway_order']) && is_array($posted_settings['easy_invoice_gateway_order'])) { $gateway_order = array_map('sanitize_key', $posted_settings['easy_invoice_gateway_order']); update_option('easy_invoice_payment_gateway_order', $gateway_order); $response['saved_options']['easy_invoice_gateway_order'] = $gateway_order; } else { update_option('easy_invoice_payment_gateway_order', []); $response['saved_options']['easy_invoice_gateway_order'] = []; } // Handle gateway display names $gateway_manager = \EasyInvoice\EasyInvoice::getInstance()->getGatewayManager(); $all_gateways = $gateway_manager->getGateways(); foreach ($all_gateways as $gateway_id => $gateway) { $display_name_key = 'easy_invoice_gateway_display_name_' . $gateway_id; if (isset($posted_settings[$display_name_key])) { $display_name = wp_strip_all_tags(wp_unslash($posted_settings[$display_name_key])); update_option($display_name_key, $display_name); $response['saved_options'][$display_name_key] = $display_name; } } // Handle gateway-specific settings try { $gateway_configs = $this->getGatewaySettingsConfigs(); foreach ($gateway_configs as $gateway_id => $gateway_config) { if (isset($gateway_config['fields']) && is_array($gateway_config['fields'])) { foreach ($gateway_config['fields'] as $option_key => $field_config) { if (isset($posted_settings[$option_key])) { $this->sanitizeAndSaveSetting($option_key, $field_config, $posted_settings[$option_key], $response); } elseif ($field_config['type'] === 'checkbox') { // Checkboxes not in POST are considered unchecked update_option($option_key, 'no'); $response['saved_options'][$option_key] = 'no'; } } } } } catch (\Exception $e) { throw $e; // Re-throw to be caught by the main try-catch } } /** * Save settings * * @return void */ public function saveSettings() { // Verify nonce if (!wp_verify_nonce($_POST['easy_invoice_settings_nonce'], 'easy_invoice_settings')) { wp_die(__('Security check failed', 'easy-invoice')); } // Check permissions if (!current_user_can('manage_options')) { wp_die(__('You do not have permission to perform this action', 'easy-invoice')); } $posted_settings = $_POST['settings'] ?? []; $settings_config = $this->get_settings_fields_config(); $response = [ 'success' => true, 'message' => __('Settings saved successfully', 'easy-invoice'), 'saved_options' => [] ]; try { // Process each section foreach ($settings_config as $section_id => $section_data) { if (isset($section_data['fields']) && is_array($section_data['fields'])) { // Handle regular fields foreach ($section_data['fields'] as $option_key => $field_config) { if (isset($posted_settings[$option_key])) { $this->sanitizeAndSaveSetting($option_key, $field_config, $posted_settings[$option_key], $response); } elseif ($field_config['type'] === 'checkbox') { // Checkboxes not in POST are considered unchecked update_option($option_key, 'no'); $response['saved_options'][$option_key] = 'no'; } } } else if (isset($section_data['subsections']) && is_array($section_data['subsections'])) { // Handle sections with subsections (like invoice, quote, email, etc.) foreach ($section_data['subsections'] as $subsection_id => $subsection_data) { if (isset($subsection_data['fields']) && is_array($subsection_data['fields'])) { foreach ($subsection_data['fields'] as $option_key => $field_config) { if (isset($posted_settings[$option_key])) { $this->sanitizeAndSaveSetting($option_key, $field_config, $posted_settings[$option_key], $response); } elseif ($field_config['type'] === 'checkbox') { // Checkboxes not in POST are considered unchecked update_option($option_key, 'no'); $response['saved_options'][$option_key] = 'no'; } } } } } } // Handle special sections like payment methods if (isset($settings_config['payment']) && isset($settings_config['payment']['is_special_section'])) { $this->savePaymentSettings($posted_settings, $response); } // Clear any caches wp_cache_flush(); // Clear settings cache $this->settings_cache = null; // Log the save action $this->log('Settings saved successfully by user: ' . get_current_user_id()); } catch (\Exception $e) { $response['success'] = false; $response['message'] = __('Error saving settings: ', 'easy-invoice') . $e->getMessage(); $this->log('Error saving settings: ' . $e->getMessage()); } // Clear settings cache to ensure new fields are recognized $this->clearCache(); // Send JSON response wp_send_json($response); } /** * Sanitize and save a single setting * * @param string $option_key The option key * @param array $field_config The field configuration * @param mixed $value The value to sanitize and save * @param array &$response The response array to update * @return void */ private function sanitizeAndSaveSetting($option_key, $field_config, $value, &$response) { if (in_array($option_key, [ 'easy_invoice_quote_accept_text', 'easy_invoice_quote_accepted_message', 'easy_invoice_quote_declined_message' ])) { } // Unslash the value to prevent double-escaping $value = wp_unslash($value); // Allow pre-sanitization filters $value = apply_filters('easy_invoice_pre_sanitize_option', $value, $option_key, $field_config); // Sanitize based on field type switch ($field_config['type']) { case 'email': $value = sanitize_email($value); break; case 'url': $value = esc_url_raw($value); break; case 'textarea': // Use wp_kses_post for textarea to allow safe HTML while preventing double-escaping $value = wp_kses_post($value); break; case 'wp_editor': // For wp_editor content, use WordPress's built-in sanitization if (is_string($value)) { // Use wp_kses_post which expects unslashed data $value = wp_kses_post($value); } break; case 'number': if (isset($field_config['step']) && strpos((string)$field_config['step'], '.') !== false) { $value = floatval(wp_strip_all_tags(easy_invoice_str_replace(',', '.', $value))); } elseif (isset($field_config['min']) && intval($field_config['min']) < 0) { $value = intval($value); } else { $value = absint($value); } break; case 'checkbox': // For checkboxes, we expect 'yes' or 'no' values $value = ($value === 'yes' || $value === '1' || $value === true) ? 'yes' : 'no'; break; case 'select': $value = sanitize_key($value); // Ensure currency codes are always uppercase if ($option_key === 'easy_invoice_currency_code') { $value = strtoupper($value); } break; case 'multiselect': // For multiselect, ensure it's an array and sanitize each value if (!is_array($value)) { $value = []; } else { $value = array_map('sanitize_key', $value); } break; default: // For regular text fields, use wp_strip_all_tags to prevent double-escaping $value = wp_strip_all_tags($value); break; } // Allow post-sanitization value modification $value = apply_filters("easy_invoice_sanitize_option_{$option_key}", $value, $field_config); $value = apply_filters('easy_invoice_sanitize_option', $value, $option_key, $field_config); // Save the setting normally update_option($option_key, $value); $response['saved_options'][$option_key] = $value; } /** * Get all settings for the plugin * * @param bool $use_cache Whether to use cached settings * @return array The settings array */ public function getSettings($use_cache = true): array { // Return cached settings if available if ($use_cache && is_array($this->settings_cache)) { return $this->settings_cache; } $settings = []; $config = $this->get_settings_fields_config(); foreach ($config as $section_id => $section_data) { if ($section_id === 'payment' && isset($section_data['gateways'])) { // Handle gateway fields specifically foreach ($section_data['gateways'] as $gateway_id => $gateway_config) { if (isset($gateway_config['fields']) && is_array($gateway_config['fields'])) { foreach ($gateway_config['fields'] as $option_key => $field_data) { $default_value = $field_data['default'] ?? ''; $settings[$option_key] = get_option($option_key, $default_value); } } } } else if (isset($section_data['subsections']) && is_array($section_data['subsections'])) { // Handle sections with subsections (like email, invoice, quote) foreach ($section_data['subsections'] as $subsection_id => $subsection_data) { if (isset($subsection_data['fields']) && is_array($subsection_data['fields'])) { foreach ($subsection_data['fields'] as $option_key => $field_data) { $default_value = $field_data['default'] ?? ''; // Handle special defaults if ($option_key === 'easy_invoice_email_from_name' && $default_value === get_bloginfo('name')) { $default_value = get_bloginfo('name'); } if ($option_key === 'easy_invoice_email_from_address' && $default_value === get_bloginfo('admin_email')) { $default_value = get_bloginfo('admin_email'); } // Check if field has a value_callback function if (isset($field_data['value_callback']) && is_callable($field_data['value_callback'])) { $settings[$option_key] = $field_data['value_callback'](); } else { // Get option value or default $settings[$option_key] = get_option($option_key, $default_value); } } } } } else if (isset($section_data['fields']) && is_array($section_data['fields'])) { foreach ($section_data['fields'] as $option_key => $field_data) { $default_value = $field_data['default'] ?? ''; // Handle special defaults if ($option_key === 'easy_invoice_email_from_name' && $default_value === get_bloginfo('name')) { $default_value = get_bloginfo('name'); } if ($option_key === 'easy_invoice_email_from_address' && $default_value === get_bloginfo('admin_email')) { $default_value = get_bloginfo('admin_email'); } // Check if field has a value_callback function if (isset($field_data['value_callback']) && is_callable($field_data['value_callback'])) { $settings[$option_key] = $field_data['value_callback'](); } else { // Get option value or default $settings[$option_key] = get_option($option_key, $default_value); } } } } // Add special array settings $settings['easy_invoice_payment_methods'] = get_option('easy_invoice_payment_methods', []); $settings['easy_invoice_payment_gateway_order'] = get_option('easy_invoice_payment_gateway_order', []); // Cache settings $this->settings_cache = $settings; // Allow third party to add/modify settings return apply_filters('easy_invoice_settings', $settings); } /** * Log debug information * * @param string $message The message to log * @return void */ protected function log(string $message): void { } /** * Initialize default settings */ public function initializeSettings() { // Initialize invoice number settings if not already set if (!get_option('easy_invoice_invoice_prefix')) { update_option('easy_invoice_invoice_prefix', 'INV-'); } if (!get_option('easy_invoice_next_invoice_number')) { update_option('easy_invoice_next_invoice_number', 1); } // Initialize other default settings if (!get_option('easy_invoice_invoice_due_days')) { update_option('easy_invoice_invoice_due_days', 30); } if (!get_option('easy_invoice_currency_code')) { update_option('easy_invoice_currency_code', 'USD'); } if (!get_option('easy_invoice_currency_symbol')) { update_option('easy_invoice_currency_symbol', '$'); } if (!get_option('easy_invoice_currency_position')) { update_option('easy_invoice_currency_position', 'left'); } if (!get_option('easy_invoice_currency_symbol_type')) { update_option('easy_invoice_currency_symbol_type', 'symbol'); } if (!get_option('easy_invoice_decimal_separator')) { update_option('easy_invoice_decimal_separator', '.'); } if (!get_option('easy_invoice_thousands_separator')) { update_option('easy_invoice_thousands_separator', ','); } if (!get_option('easy_invoice_decimal_precision')) { update_option('easy_invoice_decimal_precision', 2); } // Initialize date format setting if (!get_option('easy_invoice_date_format')) { update_option('easy_invoice_date_format', 'us'); } // Fix legacy date format values $current_date_format = get_option('easy_invoice_date_format'); if ($current_date_format === 'mdy' || $current_date_format === 'm/d/Y') { update_option('easy_invoice_date_format', 'us'); } elseif ($current_date_format === 'd/m/Y') { update_option('easy_invoice_date_format', 'uk'); } elseif ($current_date_format === 'Y-m-d') { update_option('easy_invoice_date_format', 'iso'); } // Initialize email settings if (!get_option('easy_invoice_email_from_name')) { update_option('easy_invoice_email_from_name', get_bloginfo('name')); } if (!get_option('easy_invoice_email_from_address')) { update_option('easy_invoice_email_from_address', get_bloginfo('admin_email')); } if (!get_option('easy_invoice_enable_email_styling')) { update_option('easy_invoice_enable_email_styling', 'yes'); } if (!get_option('easy_invoice_bcc_admin')) { update_option('easy_invoice_bcc_admin', 'no'); } if (!get_option('easy_invoice_admin_email')) { update_option('easy_invoice_admin_email', get_option('admin_email')); } // Initialize Text Settings $text_settings = [ 'easy_invoice_text_invoice' => __('Invoice', 'easy-invoice'), 'easy_invoice_text_invoices' => __('Invoices', 'easy-invoice'), 'easy_invoice_text_from' => __('From', 'easy-invoice'), 'easy_invoice_text_to' => __('To', 'easy-invoice'), 'easy_invoice_text_invoice_number' => __('Invoice Number', 'easy-invoice'), 'easy_invoice_text_order_number' => __('Order Number', 'easy-invoice'), 'easy_invoice_text_invoice_date' => __('Invoice Date', 'easy-invoice'), 'easy_invoice_text_due_date' => __('Due Date', 'easy-invoice'), 'easy_invoice_text_total_due' => __('Total Due', 'easy-invoice'), 'easy_invoice_text_qty' => __('Qty', 'easy-invoice'), 'easy_invoice_text_service' => __('Service', 'easy-invoice'), 'easy_invoice_text_rate_price' => __('Rate', 'easy-invoice'), 'easy_invoice_text_adjust' => __('Adjust', 'easy-invoice'), 'easy_invoice_text_sub_total' => __('Sub Total', 'easy-invoice'), 'easy_invoice_text_total' => __('Total', 'easy-invoice'), 'easy_invoice_text_tax' => __('Tax', 'easy-invoice'), 'easy_invoice_text_discount' => __('Discount', 'easy-invoice'), 'easy_invoice_text_page' => __('Page', 'easy-invoice'), 'easy_invoice_text_print' => __('Print', 'easy-invoice'), 'easy_invoice_text_download_pdf' => __('Download as PDF', 'easy-invoice'), 'easy_invoice_text_send_email' => __('Send Email', 'easy-invoice'), 'easy_invoice_text_pay_now' => __('Pay Now', 'easy-invoice'), 'easy_invoice_text_proceed_payment' => __('Proceed to payment', 'easy-invoice'), 'easy_invoice_text_payment_gateway' => __('Invoice Payment Gateway', 'easy-invoice'), 'easy_invoice_text_quote' => __('Quote', 'easy-invoice'), 'easy_invoice_text_quotes' => __('Quotes', 'easy-invoice'), 'easy_invoice_text_quote_number' => __('Quote Number', 'easy-invoice'), 'easy_invoice_text_accept_quote' => __('Accept Quote', 'easy-invoice'), 'easy_invoice_text_decline_quote' => __('Decline Quote', 'easy-invoice'), 'easy_invoice_text_decline_reason' => __('Reason for declining', 'easy-invoice'), 'easy_invoice_text_quote_amount' => __('Quote Amount', 'easy-invoice'), 'easy_invoice_text_valid_until' => __('Valid Until Date', 'easy-invoice'), 'easy_invoice_text_quote_date' => __('Quote Date', 'easy-invoice'), 'easy_invoice_text_available' => __('Available', 'easy-invoice'), 'easy_invoice_text_draft' => __('Draft', 'easy-invoice'), 'easy_invoice_text_overdue' => __('Overdue', 'easy-invoice'), 'easy_invoice_text_paid' => __('Paid', 'easy-invoice'), 'easy_invoice_text_unpaid' => __('Unpaid', 'easy-invoice'), 'easy_invoice_text_cancelled' => __('Cancelled', 'easy-invoice'), ]; foreach ($text_settings as $option_key => $default_value) { if (!get_option($option_key)) { update_option($option_key, $default_value); } } if (!get_option('easy_invoice_invoice_email_enabled')) { update_option('easy_invoice_invoice_email_enabled', 'yes'); } if (!get_option('easy_invoice_invoice_email_subject')) { update_option('easy_invoice_invoice_email_subject', __('Your Invoice #{{invoice_number}} from {{company_name}}', 'easy-invoice')); } if (!get_option('easy_invoice_invoice_email_body')) { update_option('easy_invoice_invoice_email_body', __('

📄 Your Invoice is Ready

Dear {{client_name}},

Invoice #{{invoice_number}}
{{total_amount}}
Due Date: {{due_date}}

Your invoice has been prepared and is ready for payment. You can view and download the complete invoice from the attachment or visit the link below.

📋 Payment Details:
• Invoice Number: {{invoice_number}}
• Total Amount: {{total_amount}}
• Due Date: {{due_date}}
• Payment Terms: {{payment_terms}}

🔗 View Invoice Online:
{{invoice_url}}

Shortcode: [easy_invoice_url number="{{invoice_number}}" text="View Invoice"]

⚠️ Important: Please ensure payment is received by the due date to avoid any late fees or service interruptions.

If you have any questions about this invoice, please don\'t hesitate to contact us.

Thank you for your business!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice')); } if (!get_option('easy_invoice_quote_email_enabled')) { update_option('easy_invoice_quote_email_enabled', 'yes'); } if (!get_option('easy_invoice_quote_email_subject')) { update_option('easy_invoice_quote_email_subject', __('Your Quote #{{quote_number}} from {{company_name}}', 'easy-invoice')); } if (!get_option('easy_invoice_quote_email_body')) { update_option('easy_invoice_quote_email_body', __('

Your Quote is Ready

Dear {{client_name}},

Quote #{{quote_number}}
Total Amount: {{total_amount}}
Valid Until: {{expiry_date}}

We have prepared a detailed quote for your project. You can view and download the complete quote from the attachment or visit the link below.

Quote Summary:
• Quote Number: {{quote_number}}
• Total Amount: {{total_amount}}
• Valid Until: {{expiry_date}}
• Terms: {{payment_terms}}

🔗 View Quote Online:
{{quote_url}}

Shortcode: [easy_quote_url number="{{quote_number}}" text="View Quote"]

This quote is valid until {{expiry_date}}. If you have any questions or would like to discuss any aspects of this quote, please contact us.

We look forward to working with you!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice')); } if (!get_option('easy_invoice_payment_email_enabled')) { update_option('easy_invoice_payment_email_enabled', 'yes'); } if (!get_option('easy_invoice_payment_email_subject')) { update_option('easy_invoice_payment_email_subject', __('Payment Received - Invoice #{{invoice_number}}', 'easy-invoice')); } if (!get_option('easy_invoice_payment_email_body')) { update_option('easy_invoice_payment_email_body', __('

✅ Payment Received - Thank You!

Dear {{client_name}},

Payment Confirmation
Invoice #{{invoice_number}}
{{payment_amount}}
Payment Date: {{payment_date}}
Payment Method: {{payment_method}}

We have successfully received your payment. Thank you for your prompt payment!

📊 Payment Details:
• Invoice Number: {{invoice_number}}
• Amount Paid: {{payment_amount}}
• Payment Date: {{payment_date}}
• Payment Method: {{payment_method}}
• Transaction ID: {{transaction_id}}

🎉 Status: PAID
Your payment has been processed and your account is now up to date. We appreciate your business!

If you have any questions about this payment or need a receipt, please don\'t hesitate to contact us.

Thank you for choosing our services!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice')); } } /** * Test email functionality */ public function testEmail(): void { // Verify nonce if (!wp_verify_nonce($_POST['nonce'] ?? '', 'easy_invoice_settings')) { wp_send_json_error(['message' => __('Security check failed', 'easy-invoice')]); } // Check permissions if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action', 'easy-invoice')]); } // Get test email address $test_email = sanitize_email($_POST['test_email'] ?? ''); if (empty($test_email)) { wp_send_json_error(['message' => __('Please provide a valid email address', 'easy-invoice')]); } // Test email sending $email_manager = \EasyInvoice\Services\EmailManager::getInstance(); $result = $email_manager->testEmail($test_email); if ($result['success']) { wp_send_json_success($result); } else { wp_send_json_error($result); } } /** * Test payment reminder email functionality */ public function testPaymentReminderEmail(): void { // Verify nonce if (!wp_verify_nonce($_POST['nonce'] ?? '', 'easy_invoice_settings')) { wp_send_json_error(['message' => __('Security check failed', 'easy-invoice')]); } // Check permissions if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action', 'easy-invoice')]); } // Get test email address $test_email = sanitize_email($_POST['test_email'] ?? ''); if (empty($test_email)) { wp_send_json_error(['message' => __('Please provide a valid email address', 'easy-invoice')]); } // Get payment reminder settings $subject = get_option('easy_invoice_pro_payment_reminder_subject', __('A friendly reminder - Invoice #{{invoice_number}}', 'easy-invoice-pro')); $body = get_option('easy_invoice_pro_payment_reminder_body', ''); if (empty($body)) { wp_send_json_error(['message' => __('Payment reminder email template is empty. Please configure the email message first.', 'easy-invoice')]); } // Create sample data for testing $sample_data = [ 'invoice_number' => 'TEST-001', 'client_name' => 'Test Client', 'company_name' => get_option('easy_invoice_company_name', get_bloginfo('name') ?: 'Easy Invoice'), 'company_email' => get_option('easy_invoice_company_email', get_option('admin_email', '')), 'total_amount' => '$1,000.00', 'due_date' => date('Y-m-d', strtotime('+7 days')), ]; // Replace placeholders foreach ($sample_data as $placeholder => $value) { $subject = easy_invoice_str_replace('{{' . $placeholder . '}}', $value, $subject); $body = easy_invoice_str_replace('{{' . $placeholder . '}}', $value, $body); } // Test email sending $email_manager = \EasyInvoice\Services\EmailManager::getInstance(); $result = $email_manager->sendTestTemplateEmail($test_email, $subject, $body); if ($result['success']) { wp_send_json_success($result); } else { wp_send_json_error($result); } } /** * Test template email functionality */ public function testTemplateEmail(): void { // Verify nonce if (!wp_verify_nonce($_POST['nonce'] ?? '', 'easy_invoice_settings')) { wp_send_json_error(['message' => __('Security check failed', 'easy-invoice')]); } // Check permissions if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action', 'easy-invoice')]); } // Get test email address and template type $test_email = sanitize_email($_POST['test_email'] ?? ''); $template_type = sanitize_text_field($_POST['template_type'] ?? ''); if (empty($test_email)) { wp_send_json_error(['message' => __('Please provide a valid email address', 'easy-invoice')]); } if (empty($template_type)) { wp_send_json_error(['message' => __('Template type is required', 'easy-invoice')]); } // Get the actual configured email settings $subject = ''; $body = ''; switch ($template_type) { case 'invoice_available': $subject = get_option('easy_invoice_invoice_email_subject', __('Your Invoice #{{invoice_number}} from {{company_name}}', 'easy-invoice')); $body = get_option('easy_invoice_invoice_email_body', self::getInvoiceEmailBody()); break; case 'quote_available': $subject = get_option('easy_invoice_quote_email_subject', __('Your Quote #{{quote_number}} from {{company_name}}', 'easy-invoice')); $body = get_option('easy_invoice_quote_email_body', self::getQuoteEmailBody()); break; case 'payment_received': $subject = get_option('easy_invoice_payment_email_subject', __('Payment Received - Invoice #{{invoice_number}}', 'easy-invoice')); $body = get_option('easy_invoice_payment_email_body', self::getPaymentEmailBody()); break; default: wp_send_json_error(['message' => __('Invalid template type', 'easy-invoice')]); } // Ensure we have valid strings $subject = is_string($subject) ? $subject : ''; $body = is_string($body) ? $body : ''; if (empty($subject) || empty($body)) { wp_send_json_error(['message' => __('Email template is empty or invalid', 'easy-invoice')]); } // Create sample data for testing $sample_data = [ 'invoice_number' => 'TEST-001', 'quote_number' => 'TEST-Q-001', 'client_name' => 'Test Client', 'company_name' => get_option('easy_invoice_company_name', get_bloginfo('name') ?: 'Easy Invoice'), 'company_email' => get_option('easy_invoice_company_email', get_option('admin_email', '')), 'total_amount' => '$1,000.00', 'payment_amount' => '$1,000.00', 'due_date' => date('Y-m-d', strtotime('+30 days')), 'expiry_date' => date('Y-m-d', strtotime('+30 days')), 'payment_date' => date('Y-m-d'), 'payment_method' => 'Credit Card', 'transaction_id' => 'TXN-' . uniqid(), 'payment_terms' => get_option('easy_invoice_payment_terms', __('Due on receipt', 'easy-invoice')), ]; // Ensure all sample data values are strings foreach ($sample_data as $key => $value) { $sample_data[$key] = is_string($value) ? $value : (string) $value; } // Replace placeholders in subject and body foreach ($sample_data as $placeholder => $value) { $subject = easy_invoice_str_replace('{{' . $placeholder . '}}', $value, $subject); $body = easy_invoice_str_replace('{{' . $placeholder . '}}', $value, $body); } // Test email sending $email_manager = \EasyInvoice\Services\EmailManager::getInstance(); $result = $email_manager->sendTestTemplateEmail($test_email, $subject, $body); if ($result['success']) { wp_send_json_success($result); } else { wp_send_json_error($result); } } /** * Check if quote adjust field should be shown * * @return bool True if adjust field should be shown */ public static function shouldShowQuoteAdjustField(): bool { return get_option('easy_invoice_quote_show_adjust_field', 'yes') === 'yes'; } /** * Check if invoice adjust field should be shown * * @return bool True if adjust field should be shown */ public static function shouldShowInvoiceAdjustField(): bool { return get_option('easy_invoice_invoice_show_adjust_field', 'yes') === 'yes'; } /** * Get invoice prefix * * @return string Invoice prefix */ public static function getInvoicePrefix(): string { return get_option('easy_invoice_invoice_prefix', 'EIN_'); } /** * Get invoice starting number * * @return int Invoice starting number */ public static function getInvoiceStartingNumber(): int { return (int) get_option('easy_invoice_invoice_starting_number', 0); } /** * Get invoice terms and conditions * * @return string Invoice terms and conditions */ public static function getInvoiceTermsConditions(): string { return get_option('easy_invoice_invoice_terms_conditions', __('Payment is due within 30 days from date of invoice', 'easy-invoice')); } /** * Get invoice footer text * * @return string Invoice footer text */ public static function getInvoiceFooterText(): string { return get_option('easy_invoice_invoice_footer_text', ''); } /** * Get quote prefix * * @return string Quote prefix */ public static function getQuotePrefix(): string { return get_option('easy_invoice_quote_prefix', 'EIQN_'); } /** * Get quote starting number * * @return int Quote starting number */ public static function getQuoteStartingNumber(): int { return (int) get_option('easy_invoice_quote_starting_number', 1); } /** * Get quote terms and conditions * * @return string Quote terms and conditions */ public static function getQuoteTermsConditions(): string { return get_option('easy_invoice_quote_terms_conditions', __('This quote has a fixed price. Upon acceptance, we kindly ask for a 25% deposit prior to initiating the work.', 'easy-invoice')); } /** * Get quote footer text * * @return string Quote footer text */ public static function getQuoteFooterText(): string { return get_option('easy_invoice_quote_footer_text', __('Thanks for choosing Easy Invoice', 'easy-invoice')); } /** * Check if quote accept button should be shown * * @return bool True if accept button should be shown */ public static function shouldShowQuoteAcceptButton(): bool { return get_option('easy_invoice_quote_accept_button', 'yes') === 'yes'; } /** * Get quote accept action * * @return string Quote accept action */ public static function getQuoteAcceptAction(): string { return get_option('easy_invoice_quote_accept_action', 'convert'); } /** * Get quote accept text * * @return string Quote accept text */ public static function getQuoteAcceptText(): string { return get_option('easy_invoice_quote_accept_text', __('Important: When you accept this Quote, an Invoice will be created automatically. This will form a legally binding contract.', 'easy-invoice')); } /** * Get accepted quote message * * @return string Accepted quote message */ public static function getAcceptedQuoteMessage(): string { return get_option('easy_invoice_quote_accepted_message', __('You\'ve confirmed the Quote.
We\'ll get in touch with you shortly.', 'easy-invoice')); } /** * Check if decline reason is required * * @return bool True if decline reason is required */ public static function isDeclineReasonRequired(): bool { return get_option('easy_invoice_quote_decline_reason_required', 'no') === 'yes'; } /** * Get declined quote message * * @return string Declined quote message */ public static function getDeclinedQuoteMessage(): string { return get_option('easy_invoice_quote_declined_message', ''); } // Email Settings Helper Functions /** * Check if invoice available email is enabled * * @return bool True if invoice email is enabled */ public static function isInvoiceEmailEnabled(): bool { return get_option('easy_invoice_invoice_email_enabled', 'yes') === 'yes'; } /** * Get invoice email subject * * @return string Invoice email subject */ public static function getInvoiceEmailSubject(): string { return get_option('easy_invoice_invoice_email_subject', __('Your Invoice #{{invoice_number}} from {{company_name}}', 'easy-invoice')); } /** * Get invoice email body * * @return string Invoice email body */ public static function getInvoiceEmailBody(): string { return get_option('easy_invoice_invoice_email_body', __('

📄 Your Invoice is Ready

Dear {{client_name}},

Invoice #{{invoice_number}}
{{total_amount}}
Due Date: {{due_date}}

Your invoice has been prepared and is ready for payment. You can view and download the complete invoice from the attachment.

📋 Payment Details:
• Invoice Number: {{invoice_number}}
• Total Amount: {{total_amount}}
• Due Date: {{due_date}}
• Payment Terms: {{payment_terms}}

⚠️ Important: Please ensure payment is received by the due date to avoid any late fees or service interruptions.

If you have any questions about this invoice, please do not hesitate to contact us.

Thank you for your business!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice')); } /** * Check if quote available email is enabled * * @return bool True if quote email is enabled */ public static function isQuoteEmailEnabled(): bool { return get_option('easy_invoice_quote_email_enabled', 'yes') === 'yes'; } /** * Get quote email subject * * @return string Quote email subject */ public static function getQuoteEmailSubject(): string { return get_option('easy_invoice_quote_email_subject', __('Your Quote #{{quote_number}} from {{company_name}}', 'easy-invoice')); } /** * Get quote email body * * @return string Quote email body */ public static function getQuoteEmailBody(): string { return get_option('easy_invoice_quote_email_body', __('

📋 Your Quote is Ready

Dear {{client_name}},

Quote #{{quote_number}}
{{total_amount}}
Valid Until: {{expiry_date}}

We have prepared a detailed quote for your project. You can view and download the complete quote from the attachment.

📋 Quote Summary:
• Quote Number: {{quote_number}}
• Total Amount: {{total_amount}}
• Valid Until: {{expiry_date}}
• Terms: {{payment_terms}}

⏰ Time Sensitive: This quote is valid until {{expiry_date}}. Please review and respond within this timeframe.

If you have any questions or would like to discuss any aspects of this quote, please contact us.

We look forward to working with you!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice')); } /** * Check if payment received email is enabled * * @return bool True if payment email is enabled */ public static function isPaymentEmailEnabled(): bool { return get_option('easy_invoice_payment_email_enabled', 'yes') === 'yes'; } /** * Get payment email subject * * @return string Payment email subject */ public static function getPaymentEmailSubject(): string { return get_option('easy_invoice_payment_email_subject', __('Payment Received - Invoice #{{invoice_number}}', 'easy-invoice')); } /** * Get payment email body * * @return string Payment email body */ public static function getPaymentEmailBody(): string { return get_option('easy_invoice_payment_email_body', __('

✅ Payment Received - Thank You!

Dear {{client_name}},

Payment Confirmation
Invoice #{{invoice_number}}
{{payment_amount}}
Payment Date: {{payment_date}}
Payment Method: {{payment_method}}

We have successfully received your payment. Thank you for your prompt payment!

📊 Payment Details:
• Invoice Number: {{invoice_number}}
• Amount Paid: {{payment_amount}}
• Payment Date: {{payment_date}}
• Payment Method: {{payment_method}}
• Transaction ID: {{transaction_id}}

🎉 Status: PAID
Your payment has been processed and your account is now up to date. We appreciate your business!

If you have any questions about this payment or need a receipt, please do not hesitate to contact us.

Thank you for choosing our services!

Best regards,
{{company_name}}
{{company_email}}

', 'easy-invoice')); } // ======================================== // TEXT SETTINGS HELPER FUNCTIONS // ======================================== // // USAGE IN TEMPLATES: // Instead of: echo __('Invoice', 'easy-invoice'); // Use: echo \EasyInvoice\Controllers\SettingsController::getTextInvoice(); // // Example: //

echo \EasyInvoice\Controllers\SettingsController::getTextInvoice();

//

echo \EasyInvoice\Controllers\SettingsController::getTextFrom(); : echo $company_name;

//

echo \EasyInvoice\Controllers\SettingsController::getTextTo(); : echo $client_name;

// /** * Get custom text setting with fallback to default * * @param string $key Text setting key * @param string $default Default text * @return string Custom text or default */ public static function getTextSetting(string $key, string $default): string { $option_key = 'easy_invoice_text_' . $key; return get_option($option_key, $default); } // Invoice Text Settings public static function getTextInvoice(): string { return self::getTextSetting('invoice', __('Invoice', 'easy-invoice')); } public static function getTextInvoices(): string { return self::getTextSetting('invoices', __('Invoices', 'easy-invoice')); } public static function getTextTo(): string { return self::getTextSetting('to', __('To', 'easy-invoice')); } public static function getTextInvoiceNumber(): string { return self::getTextSetting('invoice_number', __('Invoice Number', 'easy-invoice')); } public static function getTextInvoiceDate(): string { return self::getTextSetting('invoice_date', __('Invoice Date', 'easy-invoice')); } public static function getTextDueDate(): string { return self::getTextSetting('due_date', __('Due Date', 'easy-invoice')); } public static function getTextTotalDue(): string { return self::getTextSetting('total_due', __('Total Due', 'easy-invoice')); } public static function getTextQty(): string { return self::getTextSetting('qty', __('Qty', 'easy-invoice')); } public static function getTextService(): string { return self::getTextSetting('service', __('Service', 'easy-invoice')); } public static function getTextRatePrice(): string { return self::getTextSetting('rate_price', __('Rate', 'easy-invoice')); } public static function getTextAdjust(): string { return self::getTextSetting('adjust', __('Adjust', 'easy-invoice')); } public static function getTextSubTotal(): string { return self::getTextSetting('sub_total', __('Sub Total', 'easy-invoice')); } public static function getTextTotal(): string { return self::getTextSetting('total', __('Total', 'easy-invoice')); } public static function getTextTax(): string { return self::getTextSetting('tax', __('Tax', 'easy-invoice')); } public static function getTextDiscount(): string { return self::getTextSetting('discount', __('Discount', 'easy-invoice')); } public static function getTextPrint(): string { return self::getTextSetting('print', __('Print', 'easy-invoice')); } public static function getTextDownloadPdf(): string { return self::getTextSetting('download_pdf', __('Download as PDF', 'easy-invoice')); } public static function getTextSendEmail(): string { return self::getTextSetting('send_email', __('Send Email', 'easy-invoice')); } public static function getTextPayNow(): string { return self::getTextSetting('pay_now', __('Pay Now', 'easy-invoice')); } // Quote Text Settings public static function getTextQuote(): string { return self::getTextSetting('quote', __('Quote', 'easy-invoice')); } public static function getTextQuoteNumber(): string { return self::getTextSetting('quote_number', __('Quote Number', 'easy-invoice')); } public static function getTextAcceptQuote(): string { return self::getTextSetting('accept_quote', __('Accept Quote', 'easy-invoice')); } public static function getTextDeclineQuote(): string { return self::getTextSetting('decline_quote', __('Decline Quote', 'easy-invoice')); } public static function getTextDeclineReason(): string { return self::getTextSetting('decline_reason', __('Reason for declining', 'easy-invoice')); } public static function getTextValidUntil(): string { return self::getTextSetting('valid_until', __('Valid Until Date', 'easy-invoice')); } public static function getTextQuoteDate(): string { return self::getTextSetting('quote_date', __('Quote Date', 'easy-invoice')); } public static function getTextFrom(): string { return self::getTextSetting('from', __('From', 'easy-invoice')); } /** * Get the actual date format string from the stored format identifier * * @param string $format_identifier The format identifier (us, uk, iso) * @return string The actual date format string */ public static function getDateFormatString($format_identifier = null): string { if ($format_identifier === null) { $format_identifier = get_option('easy_invoice_date_format', 'us'); } switch ($format_identifier) { case 'uk': return 'd/m/Y'; case 'iso': return 'Y-m-d'; case 'us': default: return 'm/d/Y'; } } /** * Get the current date format string * * @return string The current date format string */ public static function getCurrentDateFormat(): string { return self::getDateFormatString(); } /** * Format a date using the Easy Invoice date format setting * * @param string|int $date The date to format (timestamp or date string) * @return string The formatted date */ public static function formatDate($date): string { $format = self::getCurrentDateFormat(); $timestamp = is_numeric($date) ? $date : strtotime($date); return date_i18n($format, $timestamp); } /** * AJAX handler for regenerating invoice numbers */ public function ajaxRegenerateInvoiceNumbers() { // Verify nonce $nonce = $_POST['nonce'] ?? $_POST['easy_invoice_settings_nonce'] ?? ''; if (!wp_verify_nonce($nonce, 'easy_invoice_settings')) { wp_send_json_error(['message' => __('Security check failed', 'easy-invoice')]); } // Check permissions if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action', 'easy-invoice')]); } try { // Get the current next invoice number $current_next_number = intval(get_option('easy_invoice_next_invoice_number', 1)); $prefix = get_option('easy_invoice_invoice_prefix', 'EIIN_'); // Start regeneration from the current next number $starting_number = $current_next_number; // Get all invoices ordered by creation date $invoices = get_posts([ 'post_type' => 'easy_invoice', 'post_status' => 'publish', 'numberposts' => -1, 'orderby' => 'date', 'order' => 'ASC' ]); if (empty($invoices)) { wp_send_json_success([ 'message' => __('No invoices found to regenerate', 'easy-invoice'), 'regenerated_count' => 0 ]); } $regenerated_count = 0; $current_number = $starting_number; foreach ($invoices as $invoice) { // Generate new invoice number $new_invoice_number = $prefix . str_pad($current_number, 6, '0', STR_PAD_LEFT); // Update the invoice number update_post_meta($invoice->ID, '_easy_invoice_number', $new_invoice_number); $regenerated_count++; $current_number++; } // Update the next invoice number counter to continue from the last regenerated number + 1 update_option('easy_invoice_next_invoice_number', $current_number); wp_send_json_success([ 'message' => sprintf(__('Successfully regenerated %d invoice numbers', 'easy-invoice'), $regenerated_count), 'regenerated_count' => $regenerated_count, 'next_number' => $current_number ]); } catch (Exception $e) { wp_send_json_error(['message' => __('Failed to regenerate invoice numbers', 'easy-invoice')]); } } /** * AJAX handler for regenerating quote numbers */ public function ajaxRegenerateQuoteNumbers() { // Verify nonce $nonce = $_POST['nonce'] ?? $_POST['easy_invoice_settings_nonce'] ?? ''; if (!wp_verify_nonce($nonce, 'easy_invoice_settings')) { wp_send_json_error(['message' => __('Security check failed', 'easy-invoice')]); } // Check permissions if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action', 'easy-invoice')]); } try { $current_next_number = intval(get_option('easy_invoice_next_quote_number', 1)); $prefix = get_option('easy_invoice_quote_prefix', 'QT-'); $starting_number = $current_next_number; $quotes = get_posts([ 'post_type' => 'easy_invoice_quote', 'post_status' => 'publish', 'numberposts' => -1, 'orderby' => 'date', 'order' => 'ASC', 'meta_query' => [ [ 'key' => '_easy_invoice_quote_number', 'compare' => 'EXISTS' ] ] ]); $regenerated_count = 0; $current_number = $starting_number; foreach ($quotes as $quote_post) { $new_quote_number = $prefix . str_pad($current_number, 6, '0', STR_PAD_LEFT); update_post_meta($quote_post->ID, '_easy_invoice_quote_number', $new_quote_number); $regenerated_count++; $current_number++; } update_option('easy_invoice_next_quote_number', $current_number); wp_send_json_success([ 'message' => sprintf(__('Successfully regenerated %d quote numbers', 'easy-invoice'), $regenerated_count), 'regenerated_count' => $regenerated_count, 'next_number' => $current_number ]); } catch (Exception $e) { wp_send_json_error(['message' => __('Failed to regenerate quote numbers', 'easy-invoice')]); } } }