service_name() );
}
/**
* Optional link that opens the payment app with amount and memo filled in.
*
* @param WC_Order $order Order.
* @return string Empty when the service has no such link.
*/
protected function pay_link( $order ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
return '';
}
/**
* Clean a handle before it is shown or used in a link.
*
* @param string $handle Raw handle.
* @return string
*/
protected function clean_handle( $handle ) {
return trim( (string) $handle );
}
/**
* Common constructor.
*/
public function __construct() {
$this->has_fields = false;
$this->supports = array( 'products' );
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
$this->payee_name = $this->get_option( 'payee_name' );
$this->payee_handle = $this->clean_handle( $this->get_option( 'payee_handle' ) );
$this->qr_image = $this->get_option( 'qr_image' );
$this->instructions = $this->get_option( 'instructions' );
$this->reference_prefix = $this->get_option( 'reference_prefix', 'MM' );
if ( ! defined( 'MMP_VERSION' ) && is_admin() ) {
$this->method_description .= ' ' . esc_html__( 'Want payments confirmed automatically from your bank emails? Get MemoMatch Pro.', 'memomatch' ) . '';
}
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'thankyou_page' ) );
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
}
/**
* Settings fields.
*/
public function init_form_fields() {
$service = $this->service_name();
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable', 'memomatch' ),
'type' => 'checkbox',
/* translators: %s: payment service name. */
'label' => sprintf( __( 'Accept %s payments', 'memomatch' ), $service ),
'default' => 'no',
),
'title' => array(
'title' => __( 'Title', 'memomatch' ),
'type' => 'safe_text',
'description' => __( 'What shoppers see at checkout.', 'memomatch' ),
/* translators: %s: payment service name. */
'default' => sprintf( __( 'Pay with %s', 'memomatch' ), $service ),
'desc_tip' => true,
),
'description' => array(
'title' => __( 'Description', 'memomatch' ),
'type' => 'textarea',
'description' => __( 'Shown under the title at checkout.', 'memomatch' ),
/* translators: %s: payment service name. */
'default' => sprintf( __( 'Place your order, then send the total with %s. You will get the payment details and your reference code on the next page.', 'memomatch' ), $service ),
'desc_tip' => true,
),
'payee_name' => array(
'title' => __( 'Recipient name', 'memomatch' ),
'type' => 'safe_text',
'description' => __( 'The name shoppers will see in their app when they send money, so they know they are paying the right person.', 'memomatch' ),
'default' => get_bloginfo( 'name' ),
'desc_tip' => true,
),
'payee_handle' => array(
'title' => $this->handle_label(),
'type' => 'safe_text',
'description' => $this->handle_help(),
'default' => '',
),
'qr_image' => array(
'title' => __( 'QR code image URL (optional)', 'memomatch' ),
'type' => 'url',
'description' => __( 'Upload your QR code from your banking or payment app to the Media Library and paste its URL here.', 'memomatch' ),
'default' => '',
),
'instructions' => array(
'title' => __( 'Extra instructions', 'memomatch' ),
'type' => 'textarea',
'description' => __( 'Added to the thank you page and the order email.', 'memomatch' ),
'default' => __( 'We ship your order as soon as your payment arrives.', 'memomatch' ),
'desc_tip' => true,
),
'reference_prefix' => array(
'title' => __( 'Reference prefix', 'memomatch' ),
'type' => 'safe_text',
'description' => __( 'Letters added to the start of every reference code, for example MM gives MM-1043-K7QD.', 'memomatch' ),
'default' => 'MM',
'desc_tip' => true,
),
);
}
/**
* Only offer the method when a handle is set and the store charges in US dollars.
*
* @return bool
*/
public function is_available() {
if ( '' === $this->payee_handle ) {
return false;
}
$currencies = apply_filters( 'memomatch_supported_currencies', array( 'USD' ), $this->id );
if ( ! in_array( get_woocommerce_currency(), $currencies, true ) ) {
return false;
}
return parent::is_available();
}
/**
* Build a short reference that is easy to type into a memo field.
*
* @param WC_Order $order Order.
* @return string
*/
protected function generate_reference( $order ) {
$alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$suffix = '';
for ( $i = 0; $i < 4; $i++ ) {
$suffix .= $alphabet[ wp_rand( 0, strlen( $alphabet ) - 1 ) ];
}
$prefix = strtoupper( preg_replace( '/[^A-Za-z0-9]/', '', (string) $this->reference_prefix ) );
$parts = array_filter( array( $prefix, $order->get_order_number(), $suffix ), 'strlen' );
return apply_filters( 'memomatch_reference', implode( '-', $parts ), $order, $this );
}
/**
* Get or create the reference for an order.
*
* @param WC_Order $order Order.
* @return string
*/
public function get_reference( $order ) {
$reference = $order->get_meta( self::META_REFERENCE );
if ( ! $reference ) {
$reference = $this->generate_reference( $order );
$order->update_meta_data( self::META_REFERENCE, $reference );
$order->save();
}
return $reference;
}
/**
* Place the order on hold and send the shopper to the thank you page.
*
* @param int $order_id Order ID.
* @return array
*/
public function process_payment( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) {
return array( 'result' => 'failure' );
}
$reference = $this->get_reference( $order );
if ( $order->get_total() > 0 ) {
$order->update_status(
apply_filters( 'memomatch_initial_order_status', 'on-hold', $order, $this ),
/* translators: 1: payment service name, 2: reference code. */
sprintf( __( 'Waiting for %1$s payment. Reference: %2$s', 'memomatch' ), $this->service_name(), $reference )
);
} else {
$order->payment_complete();
}
wc_maybe_reduce_stock_levels( $order_id );
WC()->cart->empty_cart();
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order ),
);
}
/**
* Thank you page box.
*
* @param int $order_id Order ID.
*/
public function thankyou_page( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order || ! $order->has_status( array( 'on-hold', 'pending' ) ) ) {
return;
}
echo $this->render_instructions( $order, false ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped in render_instructions().
}
/**
* Add payment details to the on hold email.
*
* @param WC_Order $order Order.
* @param bool $sent_to_admin Whether the email goes to the store.
* @param bool $plain_text Plain text email.
*/
public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
if ( $sent_to_admin || ! $order instanceof WC_Order || $this->id !== $order->get_payment_method() || ! $order->has_status( 'on-hold' ) ) {
return;
}
if ( $plain_text ) {
echo esc_html( $this->render_instructions_plain( $order ) ) . "\n";
$link = $this->pay_link( $order );
if ( $link ) {
echo "\n" . esc_url_raw( $link ) . "\n";
}
echo "\n";
return;
}
echo $this->render_instructions( $order, true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped in render_instructions().
}
/**
* Plain text payment details for plain text emails.
*
* @param WC_Order $order Order.
* @return string
*/
public function render_instructions_plain( $order ) {
$amount = html_entity_decode( wp_strip_all_tags( wc_price( $order->get_total(), array( 'currency' => $order->get_currency() ) ) ), ENT_QUOTES, 'UTF-8' );
$to = $this->payee_handle . ( $this->payee_name ? ' (' . $this->payee_name . ')' : '' );
/* translators: %s: payment service name. */
$lines = array( strtoupper( sprintf( __( 'How to pay with %s', 'memomatch' ), $this->service_name() ) ), '' );
$lines[] = '1. ' . $this->open_app_text();
$lines[] = '2. ' . __( 'Send to:', 'memomatch' ) . ' ' . $to;
$lines[] = '3. ' . __( 'Amount:', 'memomatch' ) . ' ' . $amount;
$lines[] = '4. ' . __( 'Write this code in the memo or note:', 'memomatch' ) . ' ' . $this->get_reference( $order );
if ( $this->instructions ) {
$lines[] = '';
$lines[] = $this->instructions;
}
return implode( "\n", $lines );
}
/**
* HTML for the payment details. All values are escaped here.
*
* @param WC_Order $order Order.
* @param bool $is_email Whether this is for an email.
* @return string
*/
public function render_instructions( $order, $is_email ) {
$reference = $this->get_reference( $order );
$amount = wp_strip_all_tags( wc_price( $order->get_total(), array( 'currency' => $order->get_currency() ) ) );
$link = $this->pay_link( $order );
$box_style = $is_email ? 'border:1px solid #e5e5e5;padding:16px;margin:0 0 24px;' : '';
ob_start();
?>
service_name() ) );
?>
- open_app_text() ); ?>
-
payee_handle ); ?>
payee_name ) : ?>
(payee_name ); ?>)
-
-
service_name() ) );
?>
qr_image ) : ?>
; ?>)
instructions ) : ?>
instructions ) ) ); ?>