├── .github └── workflows │ └── projects.yml ├── .gitignore ├── .nvmrc ├── README.md ├── bin └── build_i18n.sh ├── includes ├── blocks │ └── class-wc-dummy-payments-blocks.php └── class-wc-gateway-dummy.php ├── package.json ├── phpcs.xml ├── resources └── js │ └── frontend │ └── index.js ├── webpack.config.js └── woocommerce-gateway-dummy.php /.github/workflows/projects.yml: -------------------------------------------------------------------------------- 1 | name: Add issues and PRs to project boards 2 | on: 3 | issues: 4 | types: 5 | - labeled 6 | - opened 7 | pull_request: 8 | types: opened 9 | 10 | jobs: 11 | add-to-project: 12 | name: Add issues and PRs to project boards 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/add-to-project@v0.5.0 16 | with: 17 | project-url: https://github.com/orgs/woocommerce/projects/125 18 | github-token: ${{ secrets.ADD_TO_PROJECT }} 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Editors 2 | project.xml 3 | project.properties 4 | /nbproject/private/ 5 | .buildpath 6 | .project 7 | .settings* 8 | sftp-config.json 9 | .idea 10 | ._* 11 | 12 | # Grunt 13 | /node_modules/ 14 | /deploy/ 15 | package-lock.json 16 | 17 | # Composer 18 | /vendor/ 19 | composer.lock 20 | 21 | # Sass 22 | .sass-cache/ 23 | 24 | # OS X metadata 25 | .DS_Store 26 | 27 | # Windows junk 28 | Thumbs.db 29 | 30 | # ApiGen 31 | /wc-apidocs/ 32 | 33 | # Tests (Unit and E2E) 34 | /tmp 35 | /tests/coverage/ 36 | /tests/_output/* 37 | !/tests/_output/.gitkeep 38 | 39 | # Logs 40 | /logs 41 | 42 | # Build assets. 43 | select2.scss 44 | /assets/ 45 | /languages/ 46 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WooCommerce Dummy Payments Gateway 2 | 3 | A dummy payment gateway for your WooCommerce development needs, with built-in support for subscriptions and the block-based checkout. 4 | 5 | ### Building instructions 6 | 7 | To build this project, run: 8 | 9 | ``` 10 | nvm use 11 | npm install 12 | npm run packages-update 13 | npm run build 14 | ``` 15 | -------------------------------------------------------------------------------- /bin/build_i18n.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check for required version. 4 | WPCLI_VERSION=`wp cli version | cut -f2 -d' '` 5 | if [ ${WPCLI_VERSION:0:1} -lt "2" -o ${WPCLI_VERSION:0:1} -eq "2" -a ${WPCLI_VERSION:2:1} -lt "1" ]; then 6 | echo WP-CLI version 2.1.0 or greater is required to make JSON translation files 7 | exit 8 | fi 9 | 10 | # HELPERS. 11 | GREEN='\033[0;32m' 12 | GREY='\033[0;38m' 13 | NC='\033[0m' # No Color 14 | UNDERLINE_START='\e[4m' 15 | UNDERLINE_STOP='\e[0m' 16 | 17 | # Substitute JS source references with build references. 18 | for T in `find languages -name "*.pot"` 19 | do 20 | echo -e "\n${GREY}${UNDERLINE_START}Fixing references for: ${T}${UNDERLINE_STOP}${NC}" 21 | sed \ 22 | -e 's/ resources\/js\/frontend\/[^:]*:/ assets\/frontend\/blocks.js:/gp' \ 23 | $T | uniq > $T-build 24 | 25 | rm $T 26 | mv $T-build $T 27 | echo -e "${GREEN}Done${NC}" 28 | done 29 | -------------------------------------------------------------------------------- /includes/blocks/class-wc-dummy-payments-blocks.php: -------------------------------------------------------------------------------- 1 | settings = get_option( 'woocommerce_dummy_settings', [] ); 30 | $gateways = WC()->payment_gateways->payment_gateways(); 31 | $this->gateway = $gateways[ $this->name ]; 32 | } 33 | 34 | /** 35 | * Returns if this payment method should be active. If false, the scripts will not be enqueued. 36 | * 37 | * @return boolean 38 | */ 39 | public function is_active() { 40 | return $this->gateway->is_available(); 41 | } 42 | 43 | /** 44 | * Returns an array of scripts/handles to be registered for this payment method. 45 | * 46 | * @return array 47 | */ 48 | public function get_payment_method_script_handles() { 49 | $script_path = '/assets/js/frontend/blocks.js'; 50 | $script_asset_path = WC_Dummy_Payments::plugin_abspath() . 'assets/js/frontend/blocks.asset.php'; 51 | $script_asset = file_exists( $script_asset_path ) 52 | ? require( $script_asset_path ) 53 | : array( 54 | 'dependencies' => array(), 55 | 'version' => '1.2.0' 56 | ); 57 | $script_url = WC_Dummy_Payments::plugin_url() . $script_path; 58 | 59 | wp_register_script( 60 | 'wc-dummy-payments-blocks', 61 | $script_url, 62 | $script_asset[ 'dependencies' ], 63 | $script_asset[ 'version' ], 64 | true 65 | ); 66 | 67 | if ( function_exists( 'wp_set_script_translations' ) ) { 68 | wp_set_script_translations( 'wc-dummy-payments-blocks', 'woocommerce-gateway-dummy', WC_Dummy_Payments::plugin_abspath() . 'languages/' ); 69 | } 70 | 71 | return [ 'wc-dummy-payments-blocks' ]; 72 | } 73 | 74 | /** 75 | * Returns an array of key=>value pairs of data made available to the payment methods script. 76 | * 77 | * @return array 78 | */ 79 | public function get_payment_method_data() { 80 | return [ 81 | 'title' => $this->get_setting( 'title' ), 82 | 'description' => $this->get_setting( 'description' ), 83 | 'supports' => array_filter( $this->gateway->supports, [ $this->gateway, 'supports' ] ) 84 | ]; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /includes/class-wc-gateway-dummy.php: -------------------------------------------------------------------------------- 1 | 6 | * @package WooCommerce Dummy Payments Gateway 7 | * @since 1.0.0 8 | */ 9 | 10 | // Exit if accessed directly. 11 | if ( ! defined( 'ABSPATH' ) ) { 12 | exit; 13 | } 14 | 15 | /** 16 | * Dummy Gateway. 17 | * 18 | * @class WC_Gateway_Dummy 19 | * @version 1.10.0 20 | */ 21 | class WC_Gateway_Dummy extends WC_Payment_Gateway { 22 | 23 | /** 24 | * Payment gateway instructions. 25 | * @var string 26 | * 27 | */ 28 | protected $instructions; 29 | 30 | /** 31 | * Whether the gateway is visible for non-admin users. 32 | * @var boolean 33 | * 34 | */ 35 | protected $hide_for_non_admin_users; 36 | 37 | /** 38 | * Unique id for the gateway. 39 | * @var string 40 | * 41 | */ 42 | public $id = 'dummy'; 43 | 44 | /** 45 | * Constructor for the gateway. 46 | */ 47 | public function __construct() { 48 | 49 | $this->icon = apply_filters( 'woocommerce_dummy_gateway_icon', '' ); 50 | $this->has_fields = false; 51 | $this->supports = array( 52 | 'pre-orders', 53 | 'products', 54 | 'subscriptions', 55 | 'subscription_cancellation', 56 | 'subscription_suspension', 57 | 'subscription_reactivation', 58 | 'subscription_amount_changes', 59 | 'subscription_date_changes', 60 | 'multiple_subscriptions' 61 | ); 62 | 63 | $this->method_title = _x( 'Dummy Payment', 'Dummy payment method', 'woocommerce-gateway-dummy' ); 64 | $this->method_description = __( 'Allows dummy payments.', 'woocommerce-gateway-dummy' ); 65 | 66 | // Load the settings. 67 | $this->init_form_fields(); 68 | $this->init_settings(); 69 | 70 | // Define user set variables. 71 | $this->title = $this->get_option( 'title' ); 72 | $this->description = $this->get_option( 'description' ); 73 | $this->instructions = $this->get_option( 'instructions', $this->description ); 74 | $this->hide_for_non_admin_users = $this->get_option( 'hide_for_non_admin_users' ); 75 | 76 | // Actions. 77 | add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); 78 | add_action( 'woocommerce_scheduled_subscription_payment_dummy', array( $this, 'process_subscription_payment' ), 10, 2 ); 79 | add_action ( 'wc_pre_orders_process_pre_order_completion_payment_' . $this->id, array( $this, 'process_pre_order_release_payment' ), 10 ); 80 | } 81 | 82 | /** 83 | * Initialise Gateway Settings Form Fields. 84 | */ 85 | public function init_form_fields() { 86 | 87 | $this->form_fields = array( 88 | 'enabled' => array( 89 | 'title' => __( 'Enable/Disable', 'woocommerce-gateway-dummy' ), 90 | 'type' => 'checkbox', 91 | 'label' => __( 'Enable Dummy Payments', 'woocommerce-gateway-dummy' ), 92 | 'default' => 'yes', 93 | ), 94 | 'hide_for_non_admin_users' => array( 95 | 'type' => 'checkbox', 96 | 'label' => __( 'Hide at checkout for non-admin users', 'woocommerce-gateway-dummy' ), 97 | 'default' => 'no', 98 | ), 99 | 'title' => array( 100 | 'title' => __( 'Title', 'woocommerce-gateway-dummy' ), 101 | 'type' => 'text', 102 | 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-gateway-dummy' ), 103 | 'default' => _x( 'Dummy Payment', 'Dummy payment method', 'woocommerce-gateway-dummy' ), 104 | 'desc_tip' => true, 105 | ), 106 | 'description' => array( 107 | 'title' => __( 'Description', 'woocommerce-gateway-dummy' ), 108 | 'type' => 'textarea', 109 | 'description' => __( 'Payment method description that the customer will see on your checkout.', 'woocommerce-gateway-dummy' ), 110 | 'default' => __( 'The goods are yours. No money needed.', 'woocommerce-gateway-dummy' ), 111 | 'desc_tip' => true, 112 | ), 113 | 'result' => array( 114 | 'title' => __( 'Payment result', 'woocommerce-gateway-dummy' ), 115 | 'desc' => __( 'Determine if order payments are successful when using this gateway.', 'woocommerce-gateway-dummy' ), 116 | 'id' => 'woo_dummy_payment_result', 117 | 'type' => 'select', 118 | 'options' => array( 119 | 'success' => __( 'Success', 'woocommerce-gateway-dummy' ), 120 | 'failure' => __( 'Failure', 'woocommerce-gateway-dummy' ), 121 | ), 122 | 'default' => 'success', 123 | 'desc_tip' => true, 124 | ) 125 | ); 126 | } 127 | 128 | /** 129 | * Process the payment and return the result. 130 | * 131 | * @param int $order_id 132 | * @return array 133 | */ 134 | public function process_payment( $order_id ) { 135 | 136 | $payment_result = $this->get_option( 'result' ); 137 | $order = wc_get_order( $order_id ); 138 | 139 | if ( 'success' === $payment_result ) { 140 | // Handle pre-orders charged upon release. 141 | if ( 142 | class_exists( 'WC_Pre_Orders_Order' ) 143 | && WC_Pre_Orders_Order::order_contains_pre_order( $order ) 144 | && WC_Pre_Orders_Order::order_will_be_charged_upon_release( $order ) 145 | ) { 146 | // Mark order as tokenized (no token is saved for the dummy gateway). 147 | $order->update_meta_data( '_wc_pre_orders_has_payment_token', '1' ); 148 | $order->save_meta_data(); 149 | WC_Pre_Orders_Order::mark_order_as_pre_ordered( $order ); 150 | } else { 151 | $order->payment_complete(); 152 | } 153 | 154 | // Remove cart 155 | WC()->cart->empty_cart(); 156 | 157 | // Return thankyou redirect 158 | return array( 159 | 'result' => 'success', 160 | 'redirect' => $this->get_return_url( $order ) 161 | ); 162 | } else { 163 | $message = __( 'Order payment failed. To make a successful payment using Dummy Payments, please review the gateway settings.', 'woocommerce-gateway-dummy' ); 164 | $order->update_status( 'failed', $message ); 165 | throw new Exception( $message ); 166 | } 167 | } 168 | 169 | /** 170 | * Process subscription payment. 171 | * 172 | * @param float $amount 173 | * @param WC_Order $order 174 | * @return void 175 | */ 176 | public function process_subscription_payment( $amount, $order ) { 177 | $payment_result = $this->get_option( 'result' ); 178 | 179 | if ( 'success' === $payment_result ) { 180 | $order->payment_complete(); 181 | } else { 182 | $order->update_status( 'failed', __( 'Subscription payment failed. To make a successful payment using Dummy Payments, please review the gateway settings.', 'woocommerce-gateway-dummy' ) ); 183 | } 184 | } 185 | 186 | /** 187 | * Process pre-order payment upon order release. 188 | * 189 | * Processes the payment for pre-orders charged upon release. 190 | * 191 | * @param WC_Order $order The order object. 192 | */ 193 | public function process_pre_order_release_payment( $order ) { 194 | $payment_result = $this->get_option( 'result' ); 195 | 196 | if ( 'success' === $payment_result ) { 197 | $order->payment_complete(); 198 | } else { 199 | $message = __( 'Order payment failed. To make a successful payment using Dummy Payments, please review the gateway settings.', 'woocommerce-gateway-dummy' ); 200 | $order->update_status( 'failed', $message ); 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "woocommerce-gateway-dummy", 3 | "title": "WooCommerce Dummy Payments", 4 | "version": "1.10.0", 5 | "author": "WooCommerce", 6 | "license": "GPL-3.0+", 7 | "keywords": [], 8 | "engines": { 9 | "node": "^20.12.0", 10 | "npm": "^10.5.0" 11 | }, 12 | "devDependencies": { 13 | "@woocommerce/dependency-extraction-webpack-plugin": "2.2.0", 14 | "@wordpress/scripts": "^27.8.0", 15 | "cross-env": "7.0.3" 16 | }, 17 | "scripts": { 18 | "start": "wp-scripts start", 19 | "build": "wp-scripts build && npm run i18n:build", 20 | "i18n": "npm run i18n:build", 21 | "i18n:build": "npm run i18n:pot && ./bin/build_i18n.sh", 22 | "i18n:pot": "php -d xdebug.max_nesting_level=512 $(which wp) i18n make-pot --exclude=\"node_modules/,languages/,assets/\" --headers='{\"Report-Msgid-Bugs-To\":\"https://woocommerce.com/my-account/create-a-ticket/\", \"language-team\":\"LANGUAGE \"}' . languages/woocommerce-gateway-dummy.pot", 23 | "i18n:json": "$(which wp) i18n make-json languages --no-purge", 24 | "packages-update": "wp-scripts packages-update", 25 | "check-engines": "wp-scripts check-engines" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | SomewhereWarm Coding Standards 4 | 5 | 6 | tests/ 7 | */node_modules/* 8 | */assets/* 9 | */vendor/* 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | tests/ 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /resources/js/frontend/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { sprintf, __ } from '@wordpress/i18n'; 3 | import { registerPaymentMethod } from '@woocommerce/blocks-registry'; 4 | import { decodeEntities } from '@wordpress/html-entities'; 5 | import { getSetting } from '@woocommerce/settings'; 6 | 7 | const settings = getSetting( 'dummy_data', {} ); 8 | 9 | const defaultLabel = __( 10 | 'Dummy Payments', 11 | 'woo-gutenberg-products-block' 12 | ); 13 | 14 | const label = decodeEntities( settings.title ) || defaultLabel; 15 | /** 16 | * Content component 17 | */ 18 | const Content = () => { 19 | return decodeEntities( settings.description || '' ); 20 | }; 21 | /** 22 | * Label component 23 | * 24 | * @param {*} props Props from payment API. 25 | */ 26 | const Label = ( props ) => { 27 | const { PaymentMethodLabel } = props.components; 28 | return ; 29 | }; 30 | 31 | /** 32 | * Dummy payment method config object. 33 | */ 34 | const Dummy = { 35 | name: "dummy", 36 | label: