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 '
  1. ' . $s . '
  2. '; }, $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', 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() ); } }