init_hooks(); } /** * Initialize hooks. */ private function init_hooks() { // WooCommerce order emails. if ( class_exists( 'WooCommerce' ) ) { add_action( 'woocommerce_order_status_adp-pending', array( $this, 'send_pending_email' ), 10, 2 ); add_action( 'woocommerce_order_status_adp-proof', array( $this, 'send_proof_received_email' ), 10, 2 ); add_action( 'woocommerce_order_status_adp-approved', array( $this, 'send_approved_email' ), 10, 2 ); add_action( 'woocommerce_order_status_adp-rejected', array( $this, 'send_rejected_email' ), 10, 2 ); add_action( 'woocommerce_order_status_adp-expired', array( $this, 'send_expired_email' ), 10, 2 ); add_filter( 'woocommerce_email_classes', array( $this, 'register_email_classes' ) ); add_filter( 'woocommerce_email_enabled_customer_failed_order', array( $this, 'maybe_disable_generic_failed_email' ), 10, 2 ); } // Standalone payment emails. add_action( 'afridirect_payment_created', array( $this, 'send_standalone_created_email' ), 10, 1 ); add_action( 'afridirect_payment_created', array( $this, 'notify_admin_standalone_started' ), 10, 1 ); add_action( 'afridirect_payment_approved', array( $this, 'send_standalone_approved_email' ), 10, 1 ); add_action( 'afridirect_payment_rejected', array( $this, 'send_standalone_rejected_email' ), 10, 2 ); add_action( 'afridirect_payment_proof_uploaded', array( $this, 'send_standalone_proof_received_email' ), 10, 1 ); } /** * Send pending payment email. * * @param int $order_id Order ID. * @param WC_Order $order Order object. */ public function send_pending_email( $order_id, $order ) { if ( 'afridirect_payment' !== $order->get_payment_method() ) { return; } $mailer = WC()->mailer(); $emails = $mailer->get_emails(); if ( isset( $emails['afridirect_pending_payment'] ) ) { $emails['afridirect_pending_payment']->trigger( $order_id, $order ); } $payer = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ); $this->send_admin_notification( /* translators: %s: WooCommerce order number. */ sprintf( __( 'New payment started - Order #%s', 'afridirect-payment' ), $order->get_order_number() ), array( __( 'Order', 'afridirect-payment' ) => '#' . $order->get_order_number(), __( 'Customer', 'afridirect-payment' ) => $payer ? $payer : $order->get_billing_email(), __( 'Amount', 'afridirect-payment' ) => html_entity_decode( wp_strip_all_tags( wc_price( $order->get_total(), array( 'currency' => $order->get_currency() ) ) ), ENT_QUOTES, 'UTF-8' ), __( 'Payment method', 'afridirect-payment' ) => (string) $order->get_meta( '_afridirect_method_label' ), ), __( 'View payment', 'afridirect-payment' ), AfriDirect_Payment_Admin_UI::page_url( 'afridirect-woo-payments' ), 'started' ); } /** * Send proof received email. * * @param int $order_id Order ID. * @param WC_Order $order Order object. */ public function send_proof_received_email( $order_id, $order ) { if ( 'afridirect_payment' !== $order->get_payment_method() ) { return; } $mailer = WC()->mailer(); $emails = $mailer->get_emails(); if ( isset( $emails['afridirect_proof_received'] ) ) { $emails['afridirect_proof_received']->trigger( $order_id, $order ); } $payer = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ); $this->send_admin_notification( /* translators: %s: WooCommerce order number. */ sprintf( __( 'New payment proof to review - Order #%s', 'afridirect-payment' ), $order->get_order_number() ), array( __( 'Order', 'afridirect-payment' ) => '#' . $order->get_order_number(), __( 'Customer', 'afridirect-payment' ) => $payer ? $payer : $order->get_billing_email(), __( 'Amount', 'afridirect-payment' ) => html_entity_decode( wp_strip_all_tags( wc_price( $order->get_total(), array( 'currency' => $order->get_currency() ) ) ), ENT_QUOTES, 'UTF-8' ), __( 'Payment method', 'afridirect-payment' ) => (string) $order->get_meta( '_afridirect_method_label' ), ), __( 'Review payment', 'afridirect-payment' ), AfriDirect_Payment_Admin_UI::page_url( 'afridirect-woo-payments' ) ); } /** * Send approved email. * * @param int $order_id Order ID. * @param WC_Order $order Order object. */ public function send_approved_email( $order_id, $order ) { if ( 'afridirect_payment' !== $order->get_payment_method() ) { return; } $mailer = WC()->mailer(); $emails = $mailer->get_emails(); if ( isset( $emails['afridirect_approved'] ) ) { $emails['afridirect_approved']->trigger( $order_id, $order ); } } /** * Send rejected email. * * @param int $order_id Order ID. * @param WC_Order $order Order object. */ public function send_rejected_email( $order_id, $order ) { if ( 'afridirect_payment' !== $order->get_payment_method() ) { return; } $mailer = WC()->mailer(); $emails = $mailer->get_emails(); if ( isset( $emails['afridirect_rejected'] ) ) { $emails['afridirect_rejected']->trigger( $order_id, $order ); } } /** * Send expired email. * * @param int $order_id Order ID. * @param WC_Order $order Order object. */ public function send_expired_email( $order_id, $order ) { if ( 'afridirect_payment' !== $order->get_payment_method() ) { return; } $mailer = WC()->mailer(); $emails = $mailer->get_emails(); if ( isset( $emails['afridirect_expired'] ) ) { $emails['afridirect_expired']->trigger( $order_id, $order ); } } /** * Register email classes. * * @param array $emails Existing email classes. * @return array */ public function register_email_classes( $emails ) { // WooCommerce isn't ready yet. if ( ! class_exists( 'WC_Email' ) ) { return $emails; } // Load our email classes only when WooCommerce email base is available. if ( ! class_exists( 'AfriDirect_Payment_Email_Pending' ) ) { require AFRIDIRECT_PAYMENT_PLUGIN_DIR . 'includes/class-emails.php'; } // If the file was included but classes are still missing, fail gracefully. if ( ! class_exists( 'AfriDirect_Payment_Email_Pending' ) ) { return $emails; } $pending_email = new AfriDirect_Payment_Email_Pending(); $proof_received_email = new AfriDirect_Payment_Email_Proof_Received(); $approved_email = new AfriDirect_Payment_Email_Approved(); $rejected_email = new AfriDirect_Payment_Email_Rejected(); $expired_email = new AfriDirect_Payment_Email_Expired(); $emails[ $pending_email->id ] = $pending_email; $emails[ $proof_received_email->id ] = $proof_received_email; $emails[ $approved_email->id ] = $approved_email; $emails[ $rejected_email->id ] = $rejected_email; $emails[ $expired_email->id ] = $expired_email; return $emails; } /** * Link to the customer's payment page for a WooCommerce order. * * Uses the plugin's own page with the order key, so guest customers can open it without logging in. * * @param WC_Order $order Order. * @return string */ public static function order_page_url( $order ) { $page_id = (int) get_option( 'afridirect_pending_page_id', 0 ); $base = $page_id ? get_permalink( $page_id ) : ''; if ( ! $base ) { return $order->get_view_order_url(); } return add_query_arg( array( 'order_id' => $order->get_id(), 'order_key' => $order->get_order_key(), ), $base ); } /** * Stop WooCommerce sending its generic "order unsuccessful" email for orders the admin declined. * * The plugin sends its own rejection email, which includes the reason. * * @param bool $enabled Whether the email is enabled. * @param WC_Order|bool $order Order the email is about. * @return bool */ public function maybe_disable_generic_failed_email( $enabled, $order = false ) { if ( $enabled && $order instanceof WC_Order && 'afridirect_payment' === $order->get_payment_method() && 'declined' === $order->get_meta( '_afridirect_review_status' ) ) { return false; } return $enabled; } /** * Address that gets admin notification emails, or an empty string when that kind is switched off. * * @param string $option Option that switches this kind of notification on or off. * @return string */ private function admin_recipient( $option = 'afridirect_notify_admin' ) { if ( ! (int) get_option( $option, 1 ) ) { return ''; } $email = sanitize_email( (string) get_option( 'afridirect_notify_email', '' ) ); return is_email( $email ) ? $email : (string) get_option( 'admin_email' ); } /** * Send an HTML email. * * @param string $to Recipient. * @param string $subject Subject. * @param string $message HTML body. * @return bool Whether the email was handed to the mail system. */ private function send_html( $to, $subject, $message ) { return wp_mail( $to, $subject, $message, array( 'Content-Type: text/html; charset=UTF-8', 'From: ' . get_bloginfo( 'name' ) . ' <' . get_option( 'admin_email' ) . '>', ) ); } /** * Tell the site admin about a payment. * * @param string $subject Subject. * @param array $rows Label => value pairs shown in the email. * @param string $button_label Button text. * @param string $button_url Button link. * @param string $type 'proof' (customer uploaded proof) or 'started' (customer began a payment). */ private function send_admin_notification( $subject, $rows, $button_label, $button_url, $type = 'proof' ) { if ( 'started' === $type ) { $to = $this->admin_recipient( 'afridirect_notify_started' ); $heading = __( 'New payment started', 'afridirect-payment' ); $intro = __( 'A customer has started a payment. You will get another email when they upload proof of payment.', 'afridirect-payment' ); } else { $to = $this->admin_recipient(); $heading = __( 'New payment proof to review', 'afridirect-payment' ); $intro = __( 'A customer has uploaded proof of payment and it is waiting for your decision.', 'afridirect-payment' ); } if ( '' === $to ) { return; } $this->send_html( $to, $subject, $this->render_email( $heading, '#1f7a3d', array( $intro ), $rows, $button_label, $button_url ) ); } /** * Link to the customer's payment page for a standalone payment. * * @param array $payment Payment data from AfriDirect_Payments::get_payment(). * @return string */ private function standalone_status_url( $payment ) { return AfriDirect_Payments::get_status_url( $payment ); } /** * Payment rows shown in standalone emails. * * @param array $payment Payment data. * @return array Label => value. */ private function standalone_rows( $payment ) { return array( __( 'Reference', 'afridirect-payment' ) => $payment['reference'], __( 'Amount', 'afridirect-payment' ) => number_format( $payment['amount'], 2 ) . ' ' . strtoupper( $payment['currency'] ), __( 'Payment method', 'afridirect-payment' ) => $payment['method_label'], ); } /** * Build a simple, consistent HTML email. * * @param string $heading Heading in the coloured header. * @param string $color Header colour. * @param array $paragraphs Plain-text paragraphs. * @param array $rows Label => value pairs. * @param string $button_label Optional button text. * @param string $button_url Optional button link. * @return string */ private function render_email( $heading, $color, $paragraphs, $rows = array(), $button_label = '', $button_url = '' ) { ob_start(); ?>

$value ) : ?>
:


-

standalone_rows( $payment ); $payer = $payment['payer_name'] ? $payment['payer_name'] : $payment['payer_email']; if ( $payer ) { $rows = array( __( 'Payer', 'afridirect-payment' ) => $payer ) + $rows; } $this->send_admin_notification( /* translators: %s: Payment reference number */ sprintf( __( 'New payment started - %s', 'afridirect-payment' ), $payment['reference'] ), $rows, __( 'View payment', 'afridirect-payment' ), (string) get_edit_post_link( $payment_id, 'raw' ), 'started' ); } /** * Email a payment request to the customer. * * @param int $request_id Request ID. * @return bool Whether the email was sent. */ public function send_request_email( $request_id ) { $request = AfriDirect_Payment_Requests::get( $request_id ); if ( ! $request || '' === $request['customer_email'] || 'cancelled' === $request['status'] ) { return false; } $site = get_bloginfo( 'name' ); $date_time = get_option( 'date_format' ) . ' ' . get_option( 'time_format' ); $paragraphs = array( $request['customer_name'] /* translators: %s: Customer name. */ ? sprintf( __( 'Hello %s,', 'afridirect-payment' ), $request['customer_name'] ) : __( 'Hello,', 'afridirect-payment' ), /* translators: %s: Store name. */ sprintf( __( '%s has sent you a payment request.', 'afridirect-payment' ), $site ), ); $rows = array( __( 'Reference', 'afridirect-payment' ) => $request['reference'], __( 'Amount', 'afridirect-payment' ) => number_format( $request['amount'], 2 ) . ' ' . $request['currency'], ); if ( '' !== $request['note'] ) { $rows[ __( 'For', 'afridirect-payment' ) ] = $request['note']; } if ( $request['valid_until'] ) { $rows[ __( 'Pay by', 'afridirect-payment' ) ] = wp_date( $date_time, $request['valid_until'] ); } /* translators: %d: Number of minutes. */ $paragraphs[] = sprintf( _n( 'When you click the button below you will have %d minute to send the payment and upload your proof.', 'When you click the button below you will have %d minutes to send the payment and upload your proof.', $request['timer_minutes'], 'afridirect-payment' ), $request['timer_minutes'] ); /* translators: 1: Store name, 2: Request reference. */ $subject = sprintf( __( 'Payment request from %1$s - %2$s', 'afridirect-payment' ), $site, $request['reference'] ); $message = $this->render_email( __( 'Payment request', 'afridirect-payment' ), '#1f7a3d', $paragraphs, $rows, __( 'Pay now', 'afridirect-payment' ), AfriDirect_Payment_Requests::get_link( $request ) ); $sent = $this->send_html( $request['customer_email'], $subject, $message ); if ( $sent ) { update_post_meta( $request['id'], '_afridirect_request_emailed_at', time() ); } return (bool) $sent; } /** * Email the customer when a standalone payment is started, so they can find their payment page again. * * @param int $payment_id Payment ID. */ public function send_standalone_created_email( $payment_id ) { $payment = AfriDirect_Payments::get_payment( $payment_id ); if ( ! $payment || empty( $payment['payer_email'] ) ) { return; } $paragraphs = array( __( 'Thank you. To finish, send the payment using the details on your payment page, then upload your proof of payment there.', 'afridirect-payment' ), ); if ( ! empty( $payment['expires_at'] ) ) { /* translators: %s: Date and time the payment window closes. */ $paragraphs[] = sprintf( __( 'Please upload your proof before %s.', 'afridirect-payment' ), wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $payment['expires_at'] ) ); } /* translators: %s: Payment reference number */ $subject = sprintf( __( 'Complete your payment - %s', 'afridirect-payment' ), $payment['reference'] ); $message = $this->render_email( __( 'Complete your payment', 'afridirect-payment' ), '#1f7a3d', $paragraphs, $this->standalone_rows( $payment ), __( 'Open your payment page', 'afridirect-payment' ), $this->standalone_status_url( $payment ) ); $this->send_html( $payment['payer_email'], $subject, $message ); } /** * Send approved email for standalone payment. * * @param int $payment_id Payment ID. */ public function send_standalone_approved_email( $payment_id ) { $payment = AfriDirect_Payments::get_payment( $payment_id ); if ( ! $payment || empty( $payment['payer_email'] ) ) { return; } /* translators: %s: Payment reference number */ $subject = sprintf( __( 'Payment Approved - %s', 'afridirect-payment' ), $payment['reference'] ); $message = $this->get_standalone_approved_email_content( $payment ); wp_mail( $payment['payer_email'], $subject, $message, array( 'Content-Type: text/html; charset=UTF-8', 'From: ' . get_bloginfo( 'name' ) . ' <' . get_option( 'admin_email' ) . '>', ) ); } /** * Send rejected email for standalone payment. * * @param int $payment_id Payment ID. * @param string $reason Rejection reason. */ public function send_standalone_rejected_email( $payment_id, $reason = '' ) { $payment = AfriDirect_Payments::get_payment( $payment_id ); if ( ! $payment || empty( $payment['payer_email'] ) ) { return; } /* translators: %s: Payment reference number */ $subject = sprintf( __( 'Payment Rejected - %s', 'afridirect-payment' ), $payment['reference'] ); $message = $this->get_standalone_rejected_email_content( $payment, $reason ); wp_mail( $payment['payer_email'], $subject, $message, array( 'Content-Type: text/html; charset=UTF-8', 'From: ' . get_bloginfo( 'name' ) . ' <' . get_option( 'admin_email' ) . '>', ) ); } /** * Send proof received email for standalone payment. * * @param int $payment_id Payment ID. */ public function send_standalone_proof_received_email( $payment_id ) { $payment = AfriDirect_Payments::get_payment( $payment_id ); if ( ! $payment ) { return; } // Confirm to the customer. if ( ! empty( $payment['payer_email'] ) ) { /* translators: %s: Payment reference number */ $subject = sprintf( __( 'We received your proof of payment - %s', 'afridirect-payment' ), $payment['reference'] ); $message = $this->render_email( __( 'Proof received', 'afridirect-payment' ), '#1f7a3d', array( __( 'We have received your proof of payment and it is now being reviewed. We will email you as soon as it has been checked.', 'afridirect-payment' ) ), $this->standalone_rows( $payment ), __( 'View payment status', 'afridirect-payment' ), $this->standalone_status_url( $payment ) ); $this->send_html( $payment['payer_email'], $subject, $message ); } // Tell the site admin there is something to review. $rows = $this->standalone_rows( $payment ); $payer = $payment['payer_name'] ? $payment['payer_name'] : $payment['payer_email']; if ( $payer ) { $rows = array( __( 'Payer', 'afridirect-payment' ) => $payer ) + $rows; } $this->send_admin_notification( /* translators: %s: Payment reference number */ sprintf( __( 'New payment proof to review - %s', 'afridirect-payment' ), $payment['reference'] ), $rows, __( 'Review payment', 'afridirect-payment' ), (string) get_edit_post_link( $payment_id, 'raw' ) ); } /** * Get approved email content for standalone payment. * * @param array $payment Payment data. * @return string */ private function get_standalone_approved_email_content( $payment ) { $receipt_number = get_post_meta( $payment['id'], '_afridirect_receipt_no', true ); ob_start(); ?>

,


,