Add custom field at WooCommerce payment gateway’s settings page

If you are envolved of WooCommerce payment gateway’s development you’re probably familiar of how to define fields with an array for payment gateway’s settings page. But if you want to add a custom field you have to implement a function for it.

There are many posts on the web for how to extend WooCommerce admin fields with a custom field hook. But extending WooCommerce payment gateway’s settings page with a custom field is little bit different. Nothing was found in the web, so inspectation of WooCommerce itself was needed. After research of the abstract class WC_Payment_Gateway and his ancestor WC_Settings_API the solution was found. The method WC_Settings_API::generate_settings_html() is responsible for rendering content of the settings page. More info here:

The method checks for existence of generate_’ . $type . ‘_html() method and if you want to display and handle custom field you have to write such method in your payment gateway’s class. In this example we’re adding a custom icon field.

Step 1: Define the field in array passed to $this->form_fields.

array(
		...
				'icon' 		=> array(
					'title'    => esc_html__( 'Logo', 'text-domain' ),
					'desc' 	   => esc_html__( 'This controls the image which the user sees during checkout.', 'text-domain' ),
					'type'     => 'icon',
					'default'  => '',
					'desc_tip' => true,
				)
		...
			)

Step 2: Provide a method with field type.

public function generate_icon_html( $key, $data ) {
		$field_key = $this->get_field_key( $key );
		$defaults  = array(
			'title'             => '',
			'disabled'          => false,
			'class'             => '',
			'css'               => '',
			'placeholder'       => '',
			'type'              => 'text',
			'desc_tip'          => false,
			'description'       => '',
			'custom_attributes' => array(),
		);

                $data = wp_parse_args( $data, $defaults );

		$data['id'] 	= 'woocommerce_' . $this->id . '_icon';
		$data['value'] 	= $this->get_option( 'icon' );

		ob_start(); 
                ?>
                
                <tr valign="top">
			<th scope="row" class="titledesc">
				<label for="<?php echo esc_attr( $data['id'] ); ?>">
					<?php echo esc_html( $data['title'] ); ?>
					<span class="woocommerce-help-tip" data-tip="<?php echo esc_html( $data['desc'] ); ?>"></span>
				</label>
			</th>
			<td class="forminp forminp-<?php echo esc_attr( $data['type'] ) ?>">
				<input
					type="hidden"
					id="<?php echo esc_attr( $data['id'] ); ?>"
					name="<?php echo esc_attr( $data['id'] ); ?>"
					value="<?php echo esc_attr( $data['value'] ); ?>"
					>
				<img src="<?php echo ! empty( $data['value'] ) ? esc_url( wp_get_attachment_image_url( $data['value'], 'medium' ) ) : ''; ?>">
				<p class="controls">
					<button class="button-primary add-media">
						<?php esc_html_e( 'Add Logo', 'text-domain' ); ?>
					</button>
					<button class="button-secondary remove-media">
						<?php esc_html_e( 'Remove Logo', 'text-domain' ); ?>
					</button>
				</p>
			</td>
		</tr>  
		
		<?php
		return ob_get_clean();
	}

Step 3. Load wp.media object in Javascript and implement it with buttons click listeners to upload/browse the files library and set the value of the hidden input.

Hope you enjoy the article!