How to create a WP Simple Pay custom field?

How to create a WooCommerce Product Selection custom field in WP Simple Pay Pro?

If you’ve worked with WP Simple Pay, you know it is a great plugin to quickly integrate Stripe payment forms on a WordPress website. The ease of use of this plugin is impressive, but the flexibility it offers is even more incredible.

Let’s see how we can register our own custom form field in WP Simple Pay Pro 3.6.

The plugin code is freely available for download on Github. Just clone the repo in your wp-content/plugins folder and activate the plugin in your WordPress site admin.

Intro

WP Simple Pay Pro is a very flexible plugin: thanks to many well-thought actions and filters scattered around its code, we can easily modify the core behavior of this plugin.

In our tutorial, we will register a new type of payment form field in order to give a visitor the ability to pick a WooCommerce product from a list.

Once a product is selected, the form price will automatically be updated to the product price, so it can be bought by using Stripe.

Demo

First, let’s see the end result of what we’re about to create ⬇️

WooCommerce product select dropdown field in a WP Simple Pay Pro form.

How to develop a new custom field in a WP Simple Pay payment form?

Requirements

We are using WP Simple Pay Pro version 3.6.7. This tutorial may not work with the lite (free) version of the plugin.

Register a new set of fields

First thing first: let’s see how we can add a new WooCommerce group in the Choose a field dropdown when adding a field to a new payment form in the backend.

By default, WP Simple Pay creates 4 groups: payment, customer, standard and custom. But by using the 'simpay_custom_field_group_labels' field, we can add our own group in order to add our own field in it.

<?php
/**
 * Register a new Custom Form Fields group
 *
 * @param array $groups
 * @return array
 */
function register_woocommerce_fields_group( $groups ) {
	$groups['woocommerce'] = _x( 'WooCommerce', 'custom field group', 'simpay-wc-product' );
	return $groups;
}
add_filter( 'simpay_custom_field_group_labels', __NAMESPACE__ . '\\register_woocommerce_fields_group' );

With that code, we alter the original $groups variable to add a new custom woocommerce key. Its value is simply the readable title of the new group displayed to the admin user in the select dropdown.

Add our own custom field in the form settings

Now that we have the parent, let’s have a child! The simpay_custom_field_options filter gives us a way to tell WP Simple Pay to add a custom Product Dropdown option in the field selection dropdown.

<?php
/**
 * Register our new Product Dropdown form field type
 *
 * @param array $fields
 * @return array $fields
 */
function register_wc_product_dropdown_field( $fields ) {
	$fields['wc-product'] = [
		'label'      => esc_html__( 'Product Dropdown', 'simpay-wc-product' ),
		'type'       => 'wc-product',
		'category'   => 'woocommerce',
		'active'     => true,
		'repeatable' => true,
	];

	return $fields;
}
add_filter( 'simpay_custom_field_options', __NAMESPACE__ . '\register_wc_product_dropdown_field' );

The $fields associative array consists of multiple keyed items, each item following a specific structure:

  • the label key defines the label displayed to the user in the dropdown. It’s also displayed at the top of the settings section for each field of this type.
  • the type key indicates a unique key that will be used across other dynamic hooks we’ll use below. In our case, we’re using wc-product.
  • the category is a reference to the group we’ve just created. Here, we’re adding a new option in our new WooCommerce group, but you can use the default values:
    • payment
    • customer
    • standard
    • custom
  • active gives you the ability to disable the field. For example, you could dynamically disable a field based on some site-wide logic. This key accepts a boolean value.
  • finally, the repeatable setting is helpful if you’re only allowing one instance of your custom field per payment form. Once a field has been created, the option is grayed-out to the user and it’s impossible to add a second field of the same type. This setting is also expecting a boolean.

Output our field settings

To define our new field settings used by the admin user in the backend, we need to proceed in two steps.

Provide a template path to WP Simple Pay

Once the user selects and adds a new field in a form, WP Simple Pay will load a set of setting fields to customize its properties. The plugin is using a template file for each field type: this template file provides the HTML markup for the setting fields.

To let WPSP know the location of our settings template file, we can use the 'simpay_admin_{$type}_field_template' dynamic filter. The $type refers to what we defined previously in the simpay_custom_field_options filter: in our case, we’ll be using the simpay_admin_wc-product_field_template filter name because we registered the wc-product field type above.

<?php
/**
 * Display the new field type admin settings
 *
 * @param string $template
 * @return string $template
 */
function display_wc_product_dropdown_settings( $template ) {
	$template = SWCP_DIR . '/views/field-settings.php';

	return $template;
}
add_filter( 'simpay_admin_wc-product_field_template', __NAMESPACE__ . '\display_wc_product_dropdown_settings' );

The plugin is expecting the path of the PHP file in charge of outputting the field settings markup.

Create the template responsible of outputting the field settings

Now that Simple Pay knows which file to use, let’s write the HTML markup for our custom field settings.

Look at the wp-simple-pay-pro-3/includes/pro/admin/metaboxes/views/custom-fields/*.php to see how settings fields are registered. You can easily duplicate a file and adapt it to your needs to follow the same convention the plugin is using.

To do that, we will:

  1. follow the existing plugin fields markup, to keep the same CSS classes and stylings
  2. use the simpay_print_field() to output the input HTML code. It’s a helper function provided by the plugin that will greatly help us output our input fields.

The full template file code is visible here: we will only discuss the key part of it.

Data available in the template file

We have access to a $counter variable provided by WPSP. This is a unique integer linked to a new field instance added in the form. With it, we can generate unique ID and name attributes for each setting field that we create.

More importantly, we have also access to a $field variable in this template file. This variable gives us access to the current field data and it looks like that:

Content of a $field array containing a WP Simple Pay single field data

The shape of this array will depend on the settings you will register for your custom fields. A couple of keys are natively provided by the plugin such as:

  • order (the field position in the entire form fields set),
  • uid (a numeric unique identifier),
  • id (a string following the simpay_{$form_id}_{$field_type}_{$uid} pattern).
Displaying setting fields

The full template file code is visible here: we are only mentioning some key parts of it.

Each setting is displayed in a <tr class="simpay-panel-field"> container.

We can use the simpay_print_field() function to generate the markup for any type of input/checkbox/select/radio/textarea.

These fields will host any specific setting for our new payment form custom field.

<?php simpay_print_field( [
	'type'        => 'standard',
	'subtype'     => 'text',
	'name'        => "_simpay_custom_field[wc-product][{$counter}][label]",
	'id'          => "simpay-wc-product-label-{$counter}",
	'value'       => isset( $field['label'] ) ? $field['label'] : '',
	'class'       => [ 'simpay-field-text', 'simpay-label-input' ],
	'attributes'  => [ 'data-field-key' => $counter	],
	'description' => simpay_form_field_label_description(),
] );

A very important parameter of this function is the name parameter. You have to follow the plugin convention in order to:

  • automatically save your field data when saving the form,
  • let the plugin populate the $field array (previously described) with a new key => value pair for each setting field you create

The name should follow this structure: _simpay_custom_field[{$type}][{$counter}][{$setting_key}]. For instance, to register the label setting field, we’re using a _simpay_custom_field[wc-product][{$counter}][label] name attribute value.

To decide which input type will be generated, we pass a type parameter (with an optional subtype parameter for the standard input field). You can pass a value of:

  • checkbox to display a set of checkboxes. The values and labels of the checkboxes are passed via an array in a options parameter.
  • editor to display a WYSIWYG
  • radio to ouput radio buttons. The values and labels of the radio options are passed via an array in a options parameter.
  • select to output a select dropdown. The select options are passed via an array in a options parameter.
  • standard for a normal text input field. The subtype parameter can take any value and will let you customize the <input type> attribute to force an e-mail, telephone, number value…
Products selection setting field
<?php simpay_print_field( [
	'type'       => 'select',
	'name'       => "_simpay_custom_field[wc-product][{$counter}][products][]",
	'id'         => "simpay-wc-product-products-{$counter}",
	'value'      => isset( $field['products'] ) ? $field['products'] : '',
	'class'      => [ 'simpay-field-dropdown', 'simpay-field-text' ],
	'attributes' => [
		'data-field-key' => $counter,
		'multiple'       => true,
	],
	'options'     => \SWCP\get_wc_products(),
	'description' => esc_html__( 'Select the products that are available for sale in this form.', 'swcp' ),
] ); ?>

For our field to work, the admin needs to pick a selection of WooCommerce products to populate the select dropdown in the frontend.

Therefore, we’ve registered a 'type' => 'select' setting field and we passed an array of products (in a $product_id => $product_name format). Note that we also set the <select multiple> attribute to be true, so that we can pick more than one products in the list.

On the frontend side, we will then be able to access a $field['products'] variable holding all the products IDs that have been selected in the backend for this field.

Default settings fields

Note that some settings fields are necessary for the default plugin behavior to work :

  • the Form Field Label setting is not mandatory, but is a convention to let the user define the text label displayed before the payment form field,
  • the Stripe Metadata Label allows the user to set a different, more readable Stripe label for its form field,
  • the Field ID is a very important setting field: this is a <input type="hidden"> field and it stores the unique identifier generated by the plugin for this specific setting field instance.

Display the WooCommerce product selection field on the frontend

We’ve registered our new field and each field instance can now be customized with some settings fields. The last step is to output the field in a WPSP payment form.

The simpay_custom_field_html_for_non_native_fields filter

By hooking into this filter, your custom function will receive 3 parameters:

  • $html is the current payment form HTML markup. We will append some extra HTML code to this variable in order to output our own custom field markup.
  • $field is an array that contains all of our field settings (such as the field label, or the products list to be used to populate our dropdown).
  • $form is a SimplePay\Pro\Forms\Pro_Form object and contains all the data relative to the payment form currently being displayed.
<?php
/**
 * Output our custom field HTML in the form
 *
 * @param string $html
 * @param object $form
 * @return string $html
 */
function display_addon_checkbox_frontend_html( $html, $field, $form ) {
	if ( 'wc-product' === $field['type'] ) {
		$html .= output_wc_product_field_html( $field );
	}

	return $html;
}
add_filter( 'simpay_custom_field_html_for_non_native_fields', __NAMESPACE__ . '\display_addon_checkbox_frontend_html', 20, 3 );

Any payment form custom field will go through the simpay_custom_field_html_for_non_native_fields to get its HTML markup generated.

So we have to compare the $field['type'] value and check if we’re dealing with one of our wc-product field type. If that’s the case, we will pass the $field to a custom output_wc_product_field_html() function responsible of generating the final HTML markup for our field.

Generating the field markup in a payment form

Here is the last piece of the puzzle:

<?php
function output_wc_product_field_html( $item ) {
	$html      = '';
	$id        = isset( $item['id'] ) ? $item['id'] : '';
	$meta_name = isset( $item['metadata'] ) && ! empty( $item['metadata'] ) ? $item['metadata'] : $id;
	$label     = isset( $item['label'] ) ? $item['label'] : '';
	$name      = 'simpay_field[' . esc_attr( $meta_name ) . ']';

	if ( ! is_array( $item['products'] ) || empty( $item['products'] ) ) {
		return sprintf(
			'<div><p>%1$s</p></div>',
			esc_html__( 'You need to select at least one product in the form settings.', 'simpay-wc-product' )
		);
	}

	$id = simpay_dashify( $id );

	$label = '<p><label for="' . esc_attr( simpay_dashify( $id ) ) . '">' . $label . '</label></p>';
	$field = '<select name="' . $name . '" id="' . esc_attr( $id ) . '" class="simpay-amount-dropdown">';

	foreach ( $item['products'] as $product_id ) {
		$product = wc_get_product( (int) $product_id );

		if ( $product ) {
			$field .= sprintf(
				'<option value="%1$d" data-amount="%4$s">%2$s (%3$s)</option>',
				(int) $product->get_id(),
				esc_html( $product->get_name() ),
				$product->get_price_html(),
				$product->get_price()
			);
		}
	}

	$field .= '</select>';

	$html .= '<div class="simpay-form-control simpay-wc-product-container">';
	$html .= '<div class="simpay-checkbox-wrap simpay-field-wrap">';
	$html .= $label . $field;
	$html .= '</div>';
	$html .= '</div>';

	return $html;
}

This custom function will analyze the $item field array and outputs the HTML accordingly. In this function, you will receive all the field parameters and settings to conditionally generate the final input markup.

In our case, the products IDs available for sale are stored in the $item['products'] key. We use that key to output a single <option> in the dropdown.

By using a simpay-amount-dropdown class on our select dropdown, and by passing a data-amount attribute to every single option (containing the product price amount), we benefit from a core plugin logic that will automagically update the payment form price-to-pay with the price of the product selected in the dropdown.

Conclusion

In 4 steps, we’ve successfully customized WP Simple Pay Pro to display our own custom WooCommerce product field. Feel free to clone the repo to use it as a foundation for your own payment form customizations!

If you’re feeling stuck or need help with developing a custom WordPress/WooCommerce integration with WP Simple Pay, let’s chat!


You liked this content?

Make sure to share it on your social networks!