Settings > OrderProof.
*/
defined( 'ABSPATH' ) || exit;
class CODG_Settings {
public static function init() {
add_filter( 'woocommerce_settings_tabs_array', array( __CLASS__, 'add_tab' ), 50 );
add_action( 'woocommerce_settings_tabs_codg', array( __CLASS__, 'render' ) );
add_action( 'woocommerce_update_options_codg', array( __CLASS__, 'save' ) );
add_filter( 'plugin_action_links_' . plugin_basename( CODG_FILE ), array( __CLASS__, 'action_links' ) );
add_action( 'admin_menu', array( __CLASS__, 'add_menu' ), 60 );
add_action( 'woocommerce_admin_field_codg_otp_test', array( __CLASS__, 'render_test_field' ) );
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue' ) );
}
/**
* Step-by-step guide for connecting the store's own WhatsApp Business number.
*/
private static function setup_guide() {
$steps = array(
/* translators: %s: link to Meta for Developers */
sprintf( __( 'In %s, create an app of type Business and add the WhatsApp product.', 'orderproof' ), 'Meta for Developers' ),
__( 'In WhatsApp > API Setup, add and verify your business phone number (not one already used in the WhatsApp app), then copy its Phone number ID below.', 'orderproof' ),
/* translators: %s: link to Meta Business settings */
sprintf( __( 'In %s > Users > System users, create a system user, assign your app to it and generate a permanent token with the whatsapp_business_messaging permission. Paste it in Access token.', 'orderproof' ), 'Meta Business Settings' ),
/* translators: %s: link to WhatsApp Manager message templates */
sprintf( __( 'In %s, create a template of category Authentication with the Copy code button, in your customers\' language. When it is approved, enter its name and language code below.', 'orderproof' ), 'WhatsApp Manager' ),
__( 'Save, turn Test mode off, and use "Send test code" to check that a code reaches your own WhatsApp.', 'orderproof' ),
);
return '' . esc_html__( 'How to connect your WhatsApp Business number (about 20 minutes)', 'orderproof' ) . ''
. implode( '', array_map( function ( $s ) { return '
' . $s . '
'; }, $steps ) )
. '';
}
/**
* Script for the "Send test code" button, only on the OrderProof settings tab.
*/
public static function enqueue() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- only reads which screen is shown.
$page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
$tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : '';
// phpcs:enable
if ( 'wc-settings' !== $page || 'codg' !== $tab ) {
return;
}
wp_enqueue_script( 'codg-settings', CODG_URL . 'assets/js/settings.js', array(), CODG_VERSION, true );
wp_localize_script(
'codg-settings',
'codgSettings',
array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'codg_otp_test' ),
'sending' => __( 'Sending…', 'orderproof' ),
'failed' => __( 'Something went wrong. Reload the page and try again.', 'orderproof' ),
)
);
}
/**
* "Send test code": checks the store's Cloud API setup by sending a real code to the owner.
*/
public static function render_test_field( $field ) {
?>
OrderProof: shortcut to the settings tab, and the menu item
* Freemius hangs its Pricing / Account pages on.
*/
public static function add_menu() {
$hook = add_submenu_page(
'woocommerce',
__( 'OrderProof', 'orderproof' ),
__( 'OrderProof', 'orderproof' ),
'manage_woocommerce',
'orderproof',
'__return_null'
);
add_action(
'load-' . $hook,
function () {
// Let Freemius show its opt-in / skip screen first; Pricing stays locked until it is answered.
if ( codg_fs() && codg_fs()->is_activation_mode() ) {
return;
}
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=codg' ) );
exit;
}
);
}
public static function add_tab( $tabs ) {
$tabs['codg'] = __( 'OrderProof', 'orderproof' );
return $tabs;
}
public static function action_links( $links ) {
array_unshift( $links, '' . esc_html__( 'Settings', 'orderproof' ) . '' );
if ( ! codg_is_pro() && codg_upgrade_url() ) {
$links[] = '' . esc_html__( 'Go Pro', 'orderproof' ) . '';
}
return $links;
}
private static function otp_status() {
if ( 'yes' !== codg_opt( 'otp_enabled', 'no' ) ) {
return __( 'Off.', 'orderproof' );
}
if ( CODG_WhatsApp_OTP::is_test_mode() ) {
return __( 'On, in test mode: codes are shown on the verification page and nothing is sent.', 'orderproof' );
}
return CODG_WhatsApp_OTP::is_active()
? __( 'On: codes are sent with the WhatsApp Cloud API.', 'orderproof' )
: __( 'Not working yet: fill in the Phone number ID, access token and template name below.', 'orderproof' );
}
public static function fields() {
$fields = array(
array(
'title' => __( 'OrderProof', 'orderproof' ),
'type' => 'title',
/* translators: %d: number of blocked orders */
'desc' => sprintf( __( 'Fake or suspicious orders blocked so far: %d', 'orderproof' ), (int) get_option( 'codg_blocked_count', 0 ) ),
'id' => 'codg_general',
),
array(
'title' => __( 'Apply to', 'orderproof' ),
'desc' => __( 'Only Cash on Delivery orders (uncheck to protect all payment methods)', 'orderproof' ),
'id' => 'codg_cod_only',
'type' => 'checkbox',
'default' => 'yes',
),
array(
'title' => __( 'Awaiting confirmation status', 'orderproof' ),
'desc' => __( 'Put new COD orders in "Awaiting confirmation" until you confirm them by phone or WhatsApp', 'orderproof' ),
'id' => 'codg_use_pending_status',
'type' => 'checkbox',
'default' => 'yes',
),
array( 'type' => 'sectionend', 'id' => 'codg_general' ),
array(
'title' => __( 'WhatsApp OTP verification', 'orderproof' ),
'type' => 'title',
'desc' => __( 'Customers confirm each Cash on Delivery order with a 6-digit code sent to their WhatsApp. No SMS is used. Codes are sent from your own WhatsApp Business number with Meta\'s WhatsApp Cloud API (Meta charges a small fee per verification message). Unverified orders hold no stock and are cancelled automatically.', 'orderproof' ) . ' ' . esc_html__( 'Status:', 'orderproof' ) . ' ' . esc_html( self::otp_status() ) . self::setup_guide(),
'id' => 'codg_otp',
),
array(
'title' => __( 'Enable WhatsApp OTP', 'orderproof' ),
'desc' => __( 'Ask for a WhatsApp code before a Cash on Delivery order is accepted', 'orderproof' ),
'id' => 'codg_otp_enabled',
'type' => 'checkbox',
'default' => 'no',
),
array(
'title' => __( 'Test mode', 'orderproof' ),
'desc' => __( 'Show the code on the verification page instead of sending it. Use only to try OrderProof, never on a live store.', 'orderproof' ),
'id' => 'codg_otp_test_mode',
'type' => 'checkbox',
'default' => 'no',
),
array(
'title' => __( 'Phone number ID', 'orderproof' ),
'desc_tip' => __( 'Meta for Developers > your app > WhatsApp > API Setup.', 'orderproof' ),
'id' => 'codg_wa_phone_number_id',
'type' => 'text',
),
array(
'title' => __( 'Access token', 'orderproof' ),
'desc_tip' => __( 'A permanent System User token with the whatsapp_business_messaging permission.', 'orderproof' ),
'id' => 'codg_wa_access_token',
'type' => 'password',
),
array(
'title' => __( 'Template name', 'orderproof' ),
'desc_tip' => __( 'An approved message template of the "Authentication" category, with a copy-code button.', 'orderproof' ),
'id' => 'codg_wa_otp_template',
'type' => 'text',
'placeholder' => 'order_verification',
),
array(
'title' => __( 'Template language', 'orderproof' ),
'desc_tip' => __( 'Language code of the approved template, e.g. en_US, fr, ar, es, pt_BR.', 'orderproof' ),
'id' => 'codg_wa_otp_language',
'type' => 'text',
'default' => 'en_US',
),
array(
'title' => __( 'Check your setup', 'orderproof' ),
'id' => 'codg_otp_test',
'type' => 'codg_otp_test',
),
array(
'title' => __( 'Code valid for (minutes)', 'orderproof' ),
'id' => 'codg_otp_expiry',
'type' => 'number',
'default' => '10',
'custom_attributes' => array( 'min' => 1, 'max' => 60 ),
),
array(
'title' => __( 'Wrong codes allowed', 'orderproof' ),
'id' => 'codg_otp_max_attempts',
'type' => 'number',
'default' => '5',
'custom_attributes' => array( 'min' => 1, 'max' => 20 ),
),
array(
'title' => __( 'Cancel unverified orders after (hours)', 'orderproof' ),
'desc_tip' => __( '0 = never cancel automatically.', 'orderproof' ),
'id' => 'codg_otp_cancel_after',
'type' => 'number',
'default' => '2',
'custom_attributes' => array( 'min' => 0 ),
),
array( 'type' => 'sectionend', 'id' => 'codg_otp' ),
array(
'title' => __( 'Phone validation', 'orderproof' ),
'type' => 'title',
'desc' => __( 'Numbers are read with the calling code of the customer\'s billing country, so customers from any country can order.', 'orderproof' ),
'id' => 'codg_phone',
),
array(
'title' => __( 'Minimum digits', 'orderproof' ),
'desc_tip' => __( 'Length of the national number, without the country code and leading 0.', 'orderproof' ),
'id' => 'codg_phone_min',
'type' => 'number',
'default' => '6',
'custom_attributes' => array( 'min' => 4, 'max' => 15 ),
),
array(
'title' => __( 'Maximum digits', 'orderproof' ),
'id' => 'codg_phone_max',
'type' => 'number',
'default' => '14',
'custom_attributes' => array( 'min' => 4, 'max' => 15 ),
),
array(
'title' => __( 'Allowed prefixes (your country)', 'orderproof' ),
'desc_tip' => __( 'Optional. Mobile prefixes allowed for customers in your store\'s country, comma separated, without country code. Example for Morocco: 6, 7. Other countries are not affected.', 'orderproof' ),
'id' => 'codg_phone_prefixes',
'type' => 'text',
'placeholder' => '6, 7',
),
array(
'title' => __( 'Invalid phone message', 'orderproof' ),
'id' => 'codg_phone_message',
'type' => 'text',
'default' => __( 'Please enter a valid mobile phone number so we can confirm your order.', 'orderproof' ),
'css' => 'width:100%;max-width:600px',
),
array( 'type' => 'sectionend', 'id' => 'codg_phone' ),
array(
'title' => __( 'Duplicate orders', 'orderproof' ),
'type' => 'title',
'id' => 'codg_limit',
),
array(
'title' => __( 'Max orders per phone', 'orderproof' ),
'desc_tip' => __( '0 = no limit.', 'orderproof' ),
'id' => 'codg_limit_orders',
'type' => 'number',
'default' => '2',
'custom_attributes' => array( 'min' => 0 ),
),
array(
'title' => __( 'Within (hours)', 'orderproof' ),
'id' => 'codg_limit_hours',
'type' => 'number',
'default' => '24',
'custom_attributes' => array( 'min' => 1 ),
),
array(
'title' => __( 'Limit reached message', 'orderproof' ),
'id' => 'codg_limit_message',
'type' => 'text',
'default' => __( 'You already placed an order recently. We will contact you shortly to confirm it.', 'orderproof' ),
'css' => 'width:100%;max-width:600px',
),
array( 'type' => 'sectionend', 'id' => 'codg_limit' ),
array(
'title' => __( 'Blacklist', 'orderproof' ),
'type' => 'title',
'desc' => __( 'One value per line. You can also blacklist a customer with one click from the order page.', 'orderproof' ),
'id' => 'codg_blacklist',
),
array(
'title' => __( 'Phone numbers', 'orderproof' ),
'id' => 'codg_blacklist_phones',
'type' => 'textarea',
'css' => 'width:100%;max-width:400px;height:120px',
),
array(
'title' => __( 'Emails', 'orderproof' ),
'id' => 'codg_blacklist_emails',
'type' => 'textarea',
'css' => 'width:100%;max-width:400px;height:80px',
),
array(
'title' => __( 'IP addresses', 'orderproof' ),
'id' => 'codg_blacklist_ips',
'type' => 'textarea',
'css' => 'width:100%;max-width:400px;height:80px',
),
array(
'title' => __( 'Blocked message', 'orderproof' ),
'id' => 'codg_block_message',
'type' => 'text',
'default' => __( 'Sorry, we cannot accept this order. Please contact us.', 'orderproof' ),
'css' => 'width:100%;max-width:600px',
),
array( 'type' => 'sectionend', 'id' => 'codg_blacklist' ),
array(
'title' => __( 'WhatsApp confirmation', 'orderproof' ),
'type' => 'title',
'desc' => __( 'Message used by the "Confirm on WhatsApp" button on each order. Placeholders: {name} {order_id} {items} {total} {address} {phone} {shop}', 'orderproof' ),
'id' => 'codg_whatsapp',
),
array(
'title' => __( 'Message template', 'orderproof' ),
'id' => 'codg_wa_template',
'type' => 'textarea',
'default' => codg_default_template(),
'css' => 'width:100%;max-width:600px;height:180px',
),
array( 'type' => 'sectionend', 'id' => 'codg_whatsapp' ),
);
if ( ! codg_is_pro() && codg_upgrade_url() ) {
$fields[] = array(
'title' => __( 'OrderProof Pro', 'orderproof' ),
'type' => 'title',
'desc' => sprintf(
'%s
' .
'
%s
%s
%s
%s
%s
%s
%s',
esc_html__( 'Lose less money on refused deliveries:', 'orderproof' ),
esc_html__( 'Skip the WhatsApp code for trusted repeat customers', 'orderproof' ),
esc_html__( 'Risk score (0-100) for every order, based on customer history', 'orderproof' ),
esc_html__( 'Automatically block high-risk customers at checkout', 'orderproof' ),
esc_html__( 'Auto-blacklist customers after X refused deliveries', 'orderproof' ),
esc_html__( 'Multiple WhatsApp templates (confirmation, shipped, out for delivery)', 'orderproof' ),
esc_html__( 'Delivery success-rate report', 'orderproof' ),
esc_url( codg_upgrade_url() ),
esc_html__( 'Start free 7-day trial', 'orderproof' )
),
'id' => 'codg_pro_promo',
);
$fields[] = array( 'type' => 'sectionend', 'id' => 'codg_pro_promo' );
}
return apply_filters( 'codg_settings_fields', $fields );
}
public static function render() {
woocommerce_admin_fields( self::fields() );
}
public static function save() {
woocommerce_update_options( self::fields() );
}
}