PageSourceSearch

https://newjerseycraftbeer.com/wp-content/plugins/woocommerce/asse…/custom-place-order-button.js?ver=11.1.1

js newjerseycraftbeer.com collected 2026-10-02 11:49:44 UTC 9,708 bytes, 263 lines download raw bytes

1/**
2 * Custom Place Order Button API
3 *
4 * Shared functionality for custom place order buttons across checkout, order-pay,
5 * and add-payment-method pages. This module provides the core registration and
6 * button management logic.
7 *
8 * @since 10.6.0
9 */
10
11( function ( $ ) {
12	'use strict';
13
14	// Initialize the global wc.customPlaceOrderButton namespace
15	window.wc = window.wc || {};
16	window.wc.customPlaceOrderButton = window.wc.customPlaceOrderButton || {};
17
18	// Inject critical CSS inline to ensure it works even when themes dequeue woocommerce.css
19	( function injectStyles() {
20		var styleId = 'wc-custom-place-order-button-styles';
21		if ( document.getElementById( styleId ) ) {
22			return;
23		}
24		var style = document.createElement( 'style' );
25		style.id = styleId;
26		style.textContent = 'form.has-custom-place-order-button #place_order { display: none !important; }';
27		document.head.appendChild( style );
28	} )();
29
30	/**
31	 * Registry for custom place order buttons.
32	 * Key: gateway_id, Value: { render: function, cleanup: function }
33	 */
34	var customPlaceOrderButtons = {};
35
36	/**
37	 * Currently active custom button gateway ID, or null if using the default button.
38	 */
39	var activeCustomButtonGateway = null;
40
41	/**
42	 * Container element for the custom place order button.
43	 */
44	var $customButtonContainer = null;
45
46	/**
47	 * Get the current form element based on page context.
48	 *
49	 * @return {jQuery} The form element.
50	 */
51	function getForm() {
52		if ( $( 'form.checkout' ).length ) {
53			return $( 'form.checkout' ).first();
54		}
55		if ( $( '#order_review' ).length ) {
56			return $( '#order_review' ).first();
57		}
58		if ( $( '#add_payment_method' ).length ) {
59			return $( '#add_payment_method' ).first();
60		}
61		return $( [] );
62	}
63
64	/**
65	 * Get a list of gateway IDs with custom place order buttons from server config.
66	 *
67	 * @return {Array} List of gateway IDs
68	 */
69	function getGatewaysWithCustomButton() {
70		// Try multiple param sources for compatibility across pages
71		if ( typeof wc_checkout_params !== 'undefined' && wc_checkout_params.gateways_with_custom_place_order_button ) {
72			return wc_checkout_params.gateways_with_custom_place_order_button;
73		}
74		if ( typeof wc_add_payment_method_params !== 'undefined' && wc_add_payment_method_params.gateways_with_custom_place_order_button ) {
75			return wc_add_payment_method_params.gateways_with_custom_place_order_button;
76		}
77		return [];
78	}
79
80	/**
81	 * Check if a gateway has a custom place order button registered via a server-side flag.
82	 *
83	 * @param {string} gatewayId - The payment gateway ID
84	 * @return {boolean} True if gateway has custom button
85	 */
86	function gatewayHasCustomPlaceOrderButton( gatewayId ) {
87		return getGatewaysWithCustomButton().indexOf( gatewayId ) !== -1;
88	}
89
90	/**
91	 * Create or get the container for custom place order buttons.
92	 * The container is scoped to the current form to handle multiple forms on a page.
93	 * We're not creating the container server-side to avoid introducing a new template
94	 * that might break compatibility with subscriptions or other extensions.
95	 *
96	 * @return {jQuery} The container element
97	 */
98	function getOrCreateCustomButtonContainer() {
99		if ( $customButtonContainer && $customButtonContainer.length && $.contains( document, $customButtonContainer[ 0 ] ) ) {
100			return $customButtonContainer;
101		}
102
103		var $placeOrderButton = getForm().find( '#place_order' );
104		if ( ! $placeOrderButton.length ) {
105			return $( [] );
106		}
107
108		$customButtonContainer = $( '<div class="wc-custom-place-order-button"></div>' );
109		$placeOrderButton.after( $customButtonContainer );
110
111		return $customButtonContainer;
112	}
113
114	/**
115	 * Remove the custom button container.
116	 */
117	function removeCustomButtonContainer() {
118		if ( $customButtonContainer && $customButtonContainer.length ) {
119			$customButtonContainer.remove();
120			$customButtonContainer = null;
121		}
122	}
123
124	/**
125	 * Clean up the current custom button if any.
126	 */
127	function cleanupCurrentCustomButton() {
128		if ( activeCustomButtonGateway && customPlaceOrderButtons[ activeCustomButtonGateway ] ) {
129			try {
130				customPlaceOrderButtons[ activeCustomButtonGateway ].cleanup();
131			} catch ( e ) {
132				// Log errors to help gateway developers debug their cleanup implementation.
133				// eslint-disable-next-line no-console
134				console.error( 'Error in custom place order button cleanup:', e );
135			}
136		}
137		removeCustomButtonContainer();
138		activeCustomButtonGateway = null;
139	}
140
141	/**
142	 * Show custom place order button for a gateway, or show default button.
143	 * The `api` object is needed because the add-payment-method page is different than a checkout or a pay-for-order page.
144	 * Each page can decide how to implement the `validate` and `submit` methods.
145	 *
146	 * @param {string} gatewayId - The payment gateway ID
147	 * @param {Object} api - The API object to pass to render callback
148	 */
149	function maybeShowCustomPlaceOrderButton( gatewayId, api ) {
150		var $form = getForm();
151
152		// Clean up any displayed custom button, if any
153		if ( activeCustomButtonGateway && customPlaceOrderButtons[ activeCustomButtonGateway ] ) {
154			try {
155				customPlaceOrderButtons[ activeCustomButtonGateway ].cleanup();
156			} catch ( e ) {
157				// Log errors to help gateway developers debug their cleanup implementation.
158				// eslint-disable-next-line no-console
159				console.error( 'Error in custom place order button cleanup:', e );
160			}
161		}
162
163		var isCustomButtonRegistered = Boolean( customPlaceOrderButtons[ gatewayId ] );
164		if ( isCustomButtonRegistered ) {
165			// Hide the default button and show the custom one, instead.
166			$form.addClass( 'has-custom-place-order-button' );
167			activeCustomButtonGateway = gatewayId;
168
169			var $container = getOrCreateCustomButtonContainer();
170			$container.empty();
171
172			try {
173				customPlaceOrderButtons[ gatewayId ].render( $container.get( 0 ), api );
174			} catch ( e ) {
175				// Log errors to help gateway developers debug their render implementation.
176				// eslint-disable-next-line no-console
177				console.error( 'Error rendering custom place order button:', e );
178			}
179		} else {
180			// Only show default button if gateway doesn't have a custom button pending registration.
181			// This prevents flash when gateway JS loads after the initial click.
182			// Basically, when `__maybeShow` is called for a gateway that isn't registered yet but has the server-side flag set,
183			// we keep the default button hidden instead of flashing it.
184			if ( ! gatewayHasCustomPlaceOrderButton( gatewayId ) ) {
185				$form.removeClass( 'has-custom-place-order-button' );
186			}
187			activeCustomButtonGateway = null;
188			removeCustomButtonContainer();
189		}
190	}
191
192	/**
193	 * Hide default button immediately if selected gateway has custom button (prevents flash).
194	 *
195	 * @param {string} gatewayId - The payment gateway ID
196	 */
197	function maybeHideDefaultButtonOnInit( gatewayId ) {
198		if ( gatewayHasCustomPlaceOrderButton( gatewayId ) ) {
199			var $form = getForm();
200			$form.addClass( 'has-custom-place-order-button' );
201		}
202	}
203
204	/**
205	 * Register a custom place order button for a payment gateway.
206	 *
207	 * @param {string} gatewayId - The payment gateway ID (e.g., 'google_pay')
208	 * @param {Object} config - Configuration object
209	 * @param {Function} config.render - Function called to render the button. Receives (container, api)
210	 * @param {Function} config.cleanup - Function called when switching away from this gateway
211	 */
212	function registerCustomPlaceOrderButton( gatewayId, config ) {
213		// Silently ignore if already registered (prevents double-registration issues)
214		if ( customPlaceOrderButtons[ gatewayId ] ) {
215			return;
216		}
217
218		if ( typeof gatewayId !== 'string' || ! gatewayId ) {
219			// Log validation errors to help gateway developers fix incorrect API usage.
220			// eslint-disable-next-line no-console
221			console.error( 'wc.customPlaceOrderButton.register: gatewayId must be a non-empty string' );
222			return;
223		}
224		if ( typeof config !== 'object' || config === null ) {
225			// Log validation errors to help gateway developers fix incorrect API usage.
226			// eslint-disable-next-line no-console
227			console.error( 'wc.customPlaceOrderButton.register: config must be an object' );
228			return;
229		}
230		if ( typeof config.render !== 'function' ) {
231			// Log validation errors to help gateway developers fix incorrect API usage.
232			// eslint-disable-next-line no-console
233			console.error( 'wc.customPlaceOrderButton.register: render must be a function' );
234			return;
235		}
236		if ( typeof config.cleanup !== 'function' ) {
237			// Log validation errors to help gateway developers fix incorrect API usage.
238			// eslint-disable-next-line no-console
239			console.error( 'wc.customPlaceOrderButton.register: cleanup must be a function' );
240			return;
241		}
242
243		customPlaceOrderButtons[ gatewayId ] = config;
244
245		// If this gateway is already selected, notify that registration is complete
246		if ( getForm().find( 'input[name="payment_method"]:checked' ).val() === gatewayId ) {
247			// since this API needs to be used on checkout/pay for order/my account pages,
248			// we need to trigger a global event to ensure it's picked up by the WC Core JS used in those pages.
249			$( document.body ).trigger( 'wc_custom_place_order_button_registered', [ gatewayId ] );
250		}
251	}
252
253	// Export functions to the global namespace
254	// Public API (for gateway developers)
255	window.wc.customPlaceOrderButton.register = registerCustomPlaceOrderButton;
256
257	// Internal API (used by WooCommerce core, not for external use)
258	window.wc.customPlaceOrderButton.__maybeShow = maybeShowCustomPlaceOrderButton;
259	window.wc.customPlaceOrderButton.__maybeHideDefaultButtonOnInit = maybeHideDefaultButtonOnInit;
260	window.wc.customPlaceOrderButton.__cleanup = cleanupCurrentCustomButton;
261	window.wc.customPlaceOrderButton.__getForm = getForm;
262
263} )( jQuery );

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.