PageSourceSearch

https://ihr.org/wp-content/plugins/charitable-recurring/assets/js/charitable-recurring.js?ver=2.2.0

js ihr.org collected 2026-10-01 10:36:51 UTC 29,522 bytes, 628 lines download raw bytes

1/**
2 * Donation amount selection
3 */
4CHARITABLE_RECURRING = ( function( $ ) {
5
6    var methods = {
7        init : function() {
8            $( 'html' ).addClass( 'js' );
9
10            $( '.recurring-donation' ).find( 'input:checked' ).each( function() {
11                 $( this ).addClass( 'selected' );
12            });
13
14            // Update fallback hidden input when recurring donation amount is selected.
15            // This ensures the fallback always reflects the user's selection.
16            // @version 1.5.7 - Added fallback update on amount selection
17            $( '.recurring-donation-amounts' ).on( 'click change', 'input[name=donation_amount]', function() {
18                var $input = $( this );
19                var $form = $input.closest( 'form' );
20                var $fallback = $form.find( 'input[name=donation_amount_fallback][data-recurring="true"]' );
21
22                if ( $fallback.length && $input.val() && $input.val() !== 'recurring-custom' ) {
23                    $fallback.val( $input.val() );
24                    // Debug logging only when CHARITABLE_RECURRING_VARS.debug_enabled and form_debug are true.
25                    if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
26                         CHARITABLE_RECURRING_VARS.debug_enabled &&
27                         CHARITABLE_RECURRING_VARS.form_debug &&
28                         typeof console !== 'undefined' && console.log ) {
29                        console.log( '[Charitable Recurring] Updated fallback to:', $input.val() );
30                    }
31                }
32            });
33
34            // Toggle between recurring and one time tabs.
35            $( '.recurring-donation-options' ).on( 'change', 'input[name=recurring_donation]', function( event ) {
36                CHARITABLE_RECURRING.toggle_tabs( $( this ) );
37            });
38
39            // Hide the one-time donation period option if it's in the Recurring tab
40            $( '.charitable-recurring-donation-options .recurring-donation-period [name=recurring_donation_period][value=once]').parent().addClass('one-time-donation-period').hide();
41
42            // Toggle gateways on checkbox status.
43            $( '.recurring-donation-option' ).on( 'change', 'input[name=recurring_donation]', function( event ) {
44                if ( $( this ).is( ':checked' ) ) {
45                    CHARITABLE_RECURRING.toggle_gateways();
46                } else {
47                    CHARITABLE_RECURRING.toggle_gateways( true );
48                }
49            });
50
51            // Trigger change on load.
52            $( '.recurring-donation-options [name=recurring_donation]' ).change();
53
54            // Initialize Stripe payment method filtering for recurring donations
55            CHARITABLE_RECURRING.init_stripe_payment_method_filtering();
56        },
57
58        toggle_tabs : function( $radio ) {
59            var $form = $radio.closest( 'form' );
60
61            $form.find( '.recurring-donation-option' ).removeClass( 'selected' );
62            $( 'input[name=recurring_donation]:checked', $form ).closest( 'li' ).addClass( 'selected' );
63
64            var val = $( 'input[name=recurring_donation]:checked', $form ).val();
65
66            if ( val == 'once' ){
67                $form.find( '.charitable-recurring-donation-options' ).hide().removeClass( 'active' );
68                $form.find( '.charitable-donation-options:not(.charitable-recurring-donation-options)' ).show().addClass( 'active' );
69                $form.find( '.charitable-recurring-donation-options .recurring-donation-period .one-time-donation-period input').prop( 'checked', true );
70                CHARITABLE_RECURRING.toggle_gateways( true );
71                // Re-enable all Stripe payment methods for one-time donations
72                CHARITABLE_RECURRING.enable_all_stripe_payment_methods();
73            } else {
74                $form.find( '.charitable-recurring-donation-options' ).show().addClass( 'active' );
75                $form.find( '.charitable-donation-options:not(.charitable-recurring-donation-options)' ).hide().removeClass( 'active' );
76                CHARITABLE_RECURRING.toggle_gateways();
77                // Disable incompatible Stripe payment methods for recurring donations
78                CHARITABLE_RECURRING.disable_incompatible_stripe_payment_methods();
79            }
80        },
81
82        toggle_gateways : function( show_all ) {
83            var show_all;
84
85            if ( typeof( show_all ) === 'undefined' ){
86                show_all = false;
87            }
88
89            if ( show_all == true ){
90                $( '#charitable-gateway-selector li' ).show();
91            } else {
92                $( '#charitable-gateway-selector' ).find( 'input' ).each( function() {
93                    if ( $.inArray( $( this ).val(), Charitable_Recurring.supported_gateways ) !== -1 ){
94                        $( this ).parent().show();
95                    } else {
96                        $( this ).prop( 'checked', false ).parent().hide();
97                    }
98                } );
99            }
100
101        },
102
103        /**
104         * Initialize Stripe payment method filtering for recurring donations
105         */
106        init_stripe_payment_method_filtering : function() {
107            // Listen for changes on recurring donation inputs
108            $( document ).on( 'change', 'input[name=recurring_donation]', function() {
109                CHARITABLE_RECURRING.handle_recurring_donation_change( $( this ) );
110            } );
111
112            // Also listen for changes on recurring donation period inputs
113            $( document ).on( 'change', 'input[name=recurring_donation_period]', function() {
114                CHARITABLE_RECURRING.handle_recurring_donation_change( $( this ) );
115            } );
116
117            // Listen for gateway changes to validate donate button state
118            $( document ).on( 'change', 'input[name="gateway"]', function() {
119                CHARITABLE_RECURRING.validate_donate_button_state();
120            } );
121
122            // Listen for the charitable gateway changed event (for tab-based interface)
123            $( document ).on( 'charitable:gateway:changed', function( event, gatewayId ) {
124                CHARITABLE_RECURRING.validate_donate_button_state();
125            } );
126
127            // Add form submission prevention and button click handling
128            $( document ).on( 'submit', '.charitable-donation-form', function( e ) {
129                if ( CHARITABLE_RECURRING.is_donate_button_disabled() ) {
130                    e.preventDefault();
131                    CHARITABLE_RECURRING.show_submission_alert();
132                    return false;
133                }
134            } );
135
136            $( document ).on( 'click', 'button[type="submit"], input[type="submit"], .donate-button', function( e ) {
137                if ( CHARITABLE_RECURRING.is_donate_button_disabled() ) {
138                    e.preventDefault();
139                    CHARITABLE_RECURRING.show_submission_alert();
140                    return false;
141                }
142            } );
143
144            // Check initial state
145            CHARITABLE_RECURRING.check_recurring_donation_state();
146
147            // Also check state after a short delay to ensure all elements are loaded
148            setTimeout( function() {
149                CHARITABLE_RECURRING.check_recurring_donation_state();
150            }, 500 );
151        },
152
153        /**
154         * Handle changes in recurring donation selection
155         */
156        handle_recurring_donation_change : function( $input ) {
157            var $form = $input.closest( 'form' );
158            var is_recurring = CHARITABLE_RECURRING.is_recurring_donation_selected( $form );
159
160            // Debug logging
161            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
162                 CHARITABLE_RECURRING_VARS.debug_enabled &&
163                 typeof console !== 'undefined' && console.log ) {
164                console.log( 'Recurring donation change detected' );
165                console.log( 'Input value:', $input.val() );
166                console.log( 'Is recurring:', is_recurring );
167            }
168
169            if ( is_recurring ) {
170                CHARITABLE_RECURRING.disable_incompatible_stripe_payment_methods();
171                // Only show warning if incompatible payment methods exist on the form
172                if ( CHARITABLE_RECURRING.has_incompatible_gateways_on_form() ) {
173                    CHARITABLE_RECURRING.show_recurring_warning_message();
174                } else {
175                    CHARITABLE_RECURRING.hide_recurring_warning_message();
176                }
177            } else {
178                CHARITABLE_RECURRING.enable_all_stripe_payment_methods();
179                CHARITABLE_RECURRING.hide_recurring_warning_message();
180            }
181
182            // Validate donate button state
183            CHARITABLE_RECURRING.validate_donate_button_state();
184        },
185
186        /**
187         * Check if a recurring donation is currently selected
188         */
189        is_recurring_donation_selected : function( $form ) {
190            var $recurring_input = $form.find( 'input[name=recurring_donation]:checked' );
191            if ( $recurring_input.length === 0 ) {
192                return false;
193            }
194
195            var value = $recurring_input.val();
196
197            // Debug logging
198            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
199                 CHARITABLE_RECURRING_VARS.debug_enabled &&
200                 typeof console !== 'undefined' && console.log ) {
201                console.log( 'Recurring donation value:', value );
202            }
203
204            // Return false for "once" (one-time), true for all other recurring periods
205            // Use loose equality (==) to match existing code behavior
206            return value != 'once' && value != '' && value != undefined;
207        },
208
209        /**
210         * Check the current recurring donation state and apply appropriate filtering
211         */
212        check_recurring_donation_state : function() {
213            var $form = $( '.charitable-donation-form' );
214            if ( $form.length === 0 ) {
215                return;
216            }
217
218            var is_recurring = CHARITABLE_RECURRING.is_recurring_donation_selected( $form );
219
220            if ( is_recurring ) {
221                CHARITABLE_RECURRING.disable_incompatible_stripe_payment_methods();
222                // Only show warning if incompatible payment methods exist on the form
223                if ( CHARITABLE_RECURRING.has_incompatible_gateways_on_form() ) {
224                    CHARITABLE_RECURRING.show_recurring_warning_message();
225                } else {
226                    CHARITABLE_RECURRING.hide_recurring_warning_message();
227                }
228            } else {
229                CHARITABLE_RECURRING.enable_all_stripe_payment_methods();
230                CHARITABLE_RECURRING.hide_recurring_warning_message();
231            }
232
233            CHARITABLE_RECURRING.validate_donate_button_state();
234        },
235
236        /**
237         * Disable incompatible Stripe payment methods for recurring donations
238         */
239        disable_incompatible_stripe_payment_methods : function() {
240            // SEPA Direct Debit is recurring-capable in Charitable Pro 1.8.13.7+
241            // (declared via $supports['recurring'] on the gateway class). The
242            // server-side allow-list at charitable_recurring_get_supporting_gateways()
243            // is the source of truth for which gateways support recurring; this
244            // hardcoded list now only covers the methods that genuinely don't
245            // (ACH/BECS/Cash App).
246            var incompatible_methods = [
247                'stripe_ach_direct_debit',
248                'stripe_becs_direct_debit',
249                'stripe_cash_app'
250            ];
251
252            // Add offline gateway if the filter allows it to be disabled for recurring donations
253            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
254                 CHARITABLE_RECURRING_VARS.disable_offline_for_recurring ) {
255                incompatible_methods.push( 'offline' );
256            }
257
258            incompatible_methods.forEach( function( method_id ) {
259                var $tab = $( '.charitable-gateway-tab[data-gateway-id="' + method_id + '"]' );
260                var $radio = $( 'input[value="' + method_id + '"]' );
261
262                if ( $tab.length > 0 ) {
263                    $tab.addClass( 'disabled-for-recurring' );
264                    $tab.attr( 'title', 'This payment method is not available for recurring donations' );
265
266                    // If this method is currently selected, uncheck it
267                    if ( $radio.is( ':checked' ) ) {
268                        $radio.prop( 'checked', false ).trigger( 'change' );
269                    }
270                }
271            } );
272
273            // Also handle the legacy gateway selector format
274            $( '#charitable-gateway-selector li' ).each( function() {
275                var $li = $( this );
276                var $input = $li.find( 'input[type="radio"]' );
277                var gateway_value = $input.val();
278
279                if ( incompatible_methods.indexOf( gateway_value ) !== -1 ) {
280                    $li.addClass( 'disabled-for-recurring' );
281                    $li.attr( 'title', 'This payment method is not available for recurring donations' );
282
283                    if ( $input.is( ':checked' ) ) {
284                        $input.prop( 'checked', false ).trigger( 'change' );
285                    }
286                }
287            } );
288        },
289
290        /**
291         * Re-enable all Stripe payment methods
292         */
293        enable_all_stripe_payment_methods : function() {
294            // Remove disabled state from all payment method tabs
295            $( '.charitable-gateway-tab.disabled-for-recurring' ).removeClass( 'disabled-for-recurring' ).removeAttr( 'title' );
296
297            // Remove disabled state from legacy gateway selector
298            $( '#charitable-gateway-selector li.disabled-for-recurring' ).removeClass( 'disabled-for-recurring' ).removeAttr( 'title' );
299        },
300
301        /**
302         * Show warning message about payment method limitations for recurring donations
303         */
304        show_recurring_warning_message : function() {
305            // Debug logging
306            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
307                 CHARITABLE_RECURRING_VARS.debug_enabled &&
308                 typeof console !== 'undefined' && console.log ) {
309                console.log( 'Showing recurring payment warning message' );
310            }
311
312            var $warning = $( '.charitable-recurring-payment-method-warning' );
313
314            if ( $warning.length === 0 ) {
315                // Get the customizable warning message via WordPress filter
316                var warning_message = CHARITABLE_RECURRING.get_warning_message();
317
318                $warning = $( '<div class="charitable-recurring-payment-method-warning charitable-notice charitable-notice-warning">' +
319                    '<p><strong>Note:</strong> ' + warning_message + '</p></div>' );
320
321                // Insert the warning above the gateway tabs
322                var $gateway_tabs = $( '#charitable-gateway-tabs' );
323                if ( $gateway_tabs.length > 0 ) {
324                    $gateway_tabs.before( $warning );
325                } else {
326                    // Fallback: insert above the gateway selector
327                    var $gateway_selector = $( '#charitable-gateway-selector' );
328                    if ( $gateway_selector.length > 0 ) {
329                        $gateway_selector.before( $warning );
330                    } else {
331                        // Final fallback: insert before the gateway fields
332                        $( '#charitable-gateway-fields' ).prepend( $warning );
333                    }
334                }
335            }
336
337            $warning.show();
338
339            // Ensure the warning spans full width
340            $warning.css({
341                'width': '100%',
342                'display': 'block',
343                'box-sizing': 'border-box'
344            });
345        },
346
347        /**
348         * Hide the recurring payment warning message
349         */
350        hide_recurring_warning_message : function() {
351            // Debug logging
352            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
353                 CHARITABLE_RECURRING_VARS.debug_enabled &&
354                 typeof console !== 'undefined' && console.log ) {
355                console.log( 'Hiding recurring payment warning message' );
356                console.log( 'Warning elements found:', $( '.charitable-recurring-payment-method-warning' ).length );
357            }
358
359            $( '.charitable-recurring-payment-method-warning' ).remove();
360        },
361
362        /**
363         * Validate the donate button state based on selected payment method
364         */
365        validate_donate_button_state : function() {
366            var $form = $( '.charitable-donation-form' );
367            var is_recurring = this.is_recurring_donation_selected($form);
368            var $submit_button = $form.find('button[type="submit"], input[type="submit"], .donate-button');
369
370            // Debug logging
371            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
372                 CHARITABLE_RECURRING_VARS.debug_enabled &&
373                 typeof console !== 'undefined' && console.log ) {
374                console.log('validate_donate_button_state called');
375                console.log('Form found:', $form.length);
376                console.log('Submit button found:', $submit_button.length);
377                console.log('Is recurring:', is_recurring);
378                console.log('Submit button disabled:', $submit_button.prop('disabled'));
379                console.log('Submit button classes:', $submit_button.attr('class'));
380            }
381
382            if (is_recurring) {
383                // Try multiple ways to detect the selected gateway
384                var selected_gateway = this.get_selected_gateway($form);
385                // See note in disable_incompatible_stripe_payment_methods —
386                // SEPA Direct Debit is now recurring-capable.
387                var incompatible_methods = [
388                    'stripe_ach_direct_debit',
389                    'stripe_becs_direct_debit',
390                    'stripe_cash_app'
391                ];
392
393                // Add offline gateway if the filter allows it to be disabled for recurring donations
394                if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
395                     CHARITABLE_RECURRING_VARS.disable_offline_for_recurring ) {
396                    incompatible_methods.push( 'offline' );
397                }
398
399                if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
400                     CHARITABLE_RECURRING_VARS.debug_enabled &&
401                     typeof console !== 'undefined' && console.log ) {
402                    console.log('Selected gateway:', selected_gateway);
403                    console.log('Incompatible methods:', incompatible_methods);
404                    console.log('Is incompatible:', incompatible_methods.indexOf(selected_gateway) !== -1);
405                }
406
407                if (incompatible_methods.indexOf(selected_gateway) !== -1) {
408                    $submit_button.prop('disabled', true).addClass('disabled-for-recurring');
409                    this.show_donate_button_error();
410                    if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
411                         CHARITABLE_RECURRING_VARS.debug_enabled &&
412                         typeof console !== 'undefined' && console.log ) {
413                        console.log('Button disabled and error shown');
414                    }
415                } else {
416                    $submit_button.prop('disabled', false).removeClass('disabled-for-recurring');
417                    this.hide_donate_button_error();
418                    if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
419                         CHARITABLE_RECURRING_VARS.debug_enabled &&
420                         typeof console !== 'undefined' && console.log ) {
421                        console.log('Button enabled and error hidden');
422                    }
423                }
424            } else {
425                $submit_button.prop('disabled', false).removeClass('disabled-for-recurring');
426                this.hide_donate_button_error();
427                if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
428                     CHARITABLE_RECURRING_VARS.debug_enabled &&
429                     typeof console !== 'undefined' && console.log ) {
430                    console.log('Not recurring - button enabled');
431                }
432            }
433        },
434
435        /**
436         * Get the currently selected gateway using multiple detection methods
437         *
438         * @param {jQuery} $form The form element
439         * @returns {string} The selected gateway ID or empty string
440         */
441        get_selected_gateway: function($form) {
442            // Debug: Log all gateway-related elements
443            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
444                 CHARITABLE_RECURRING_VARS.debug_enabled &&
445                 typeof console !== 'undefined' && console.log ) {
446                console.log('=== Gateway Detection Debug ===');
447                console.log('All gateway inputs:', $form.find('input[name="gateway"]').length);
448                console.log('All gateway fields:', $form.find('.charitable-gateway-fields').length);
449                console.log('All gateway tabs:', $form.find('.charitable-gateway-tab').length);
450                console.log('Visible gateway fields:', $form.find('.charitable-gateway-fields:visible').length);
451            }
452
453            // Method 1: Check for standard gateway input
454            var $gateway_input = $form.find('input[name="gateway"]:checked');
455            if ($gateway_input.length) {
456                if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
457                     CHARITABLE_RECURRING_VARS.debug_enabled &&
458                     typeof console !== 'undefined' && console.log ) {
459                    console.log('Gateway found via input[name="gateway"]:', $gateway_input.val());
460                }
461                return $gateway_input.val();
462            }
463
464            // Method 2: Check for gateway in data attributes
465            var $gateway_fields = $form.find('.charitable-gateway-fields[data-gateway]');
466            if ($gateway_fields.length) {
467                var gateway = $gateway_fields.filter(':visible').first().attr('data-gateway');
468                if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
469                     CHARITABLE_RECURRING_VARS.debug_enabled &&
470                     typeof console !== 'undefined' && console.log ) {
471                    console.log('Gateway found via data-gateway attribute:', gateway);
472                }
473                return gateway;
474            }
475
476            // Method 3: Check for active gateway tab
477            var $active_tab = $form.find('.charitable-gateway-tab.active, .charitable-gateway-tab.selected');
478            if ($active_tab.length) {
479                var gateway = $active_tab.attr('data-gateway-id') || $active_tab.attr('id');
480                if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
481                     CHARITABLE_RECURRING_VARS.debug_enabled &&
482                     typeof console !== 'undefined' && console.log ) {
483                    console.log('Gateway found via active tab:', gateway);
484                }
485                return gateway;
486            }
487
488            // Method 4: Check for visible gateway fields
489            var $visible_fields = $form.find('.charitable-gateway-fields:visible');
490            if ($visible_fields.length) {
491                var gateway = $visible_fields.first().attr('data-gateway');
492                if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
493                     CHARITABLE_RECURRING_VARS.debug_enabled &&
494                     typeof console !== 'undefined' && console.log ) {
495                    console.log('Gateway found via visible fields:', gateway);
496                }
497                return gateway;
498            }
499
500            // Method 5: Check for any input with gateway-related names
501            var $any_gateway_input = $form.find('input[name*="gateway"], input[name*="payment"], input[name*="stripe"]');
502            if ($any_gateway_input.length) {
503                if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
504                     CHARITABLE_RECURRING_VARS.debug_enabled &&
505                     typeof console !== 'undefined' && console.log ) {
506                    console.log('Found inputs with gateway-related names:', $any_gateway_input.map(function() { return this.name + '=' + this.value; }).get());
507                }
508            }
509
510            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
511                 CHARITABLE_RECURRING_VARS.debug_enabled &&
512                 typeof console !== 'undefined' && console.log ) {
513                console.log('No gateway detected');
514            }
515            return '';
516        },
517
518        /**
519         * Check if the donate button is currently disabled
520         *
521         * @returns {boolean}
522         */
523        is_donate_button_disabled: function() {
524            var $form = $('.charitable-donation-form');
525            var $submit_button = $form.find('button[type="submit"], input[type="submit"], .donate-button');
526            return $submit_button.hasClass('disabled-for-recurring') || $submit_button.prop('disabled');
527        },
528
529        /**
530         * Show alert when user tries to submit with disabled button
531         */
532        show_submission_alert: function() {
533            alert('The selected payment method is not available with recurring donations at this time. Please choose a different payment method.');
534        },
535
536        /**
537         * Show donate button error message
538         */
539        show_donate_button_error: function() {
540            if ($('.charitable-recurring-payment-method-error').length) {
541                return;
542            }
543
544            var $error = $('<div class="charitable-recurring-payment-method-error charitable-notice charitable-notice-error">' +
545                '<p>The selected payment method is not available with recurring donations at this time. Please choose a different payment method.</p>' +
546                '</div>');
547
548            var $form = $('.charitable-donation-form');
549            $form.find('button[type="submit"], input[type="submit"], .donate-button').after($error);
550        },
551
552        /**
553         * Hide donate button error message
554         */
555        hide_donate_button_error: function() {
556            $('.charitable-recurring-payment-method-error').remove();
557        },
558
559        /**
560         * Check if any incompatible gateways are present on the donation form
561         *
562         * @returns {boolean}
563         */
564        has_incompatible_gateways_on_form : function() {
565            // See note in disable_incompatible_stripe_payment_methods —
566            // SEPA Direct Debit is now recurring-capable.
567            var incompatible_methods = [
568                'stripe_ach_direct_debit',
569                'stripe_becs_direct_debit',
570                'stripe_cash_app'
571            ];
572
573            // Add offline gateway if the filter allows it to be disabled for recurring donations
574            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
575                 CHARITABLE_RECURRING_VARS.disable_offline_for_recurring ) {
576                incompatible_methods.push( 'offline' );
577            }
578
579            var found = false;
580
581            incompatible_methods.forEach( function( method_id ) {
582                // Check for tab-based UI
583                if ( $( '.charitable-gateway-tab[data-gateway-id="' + method_id + '"]' ).length > 0 ) {
584                    found = true;
585                }
586                // Check for radio/hidden input-based UI
587                if ( $( 'input[name="gateway"][value="' + method_id + '"]' ).length > 0 ) {
588                    found = true;
589                }
590                // Check for legacy gateway selector
591                if ( $( '#charitable-gateway-selector input[value="' + method_id + '"]' ).length > 0 ) {
592                    found = true;
593                }
594            } );
595
596            return found;
597        },
598
599        /**
600         * Get the customizable warning message via WordPress filter
601         */
602        get_warning_message : function() {
603            // Get the localized message from WordPress
604            if ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' && CHARITABLE_RECURRING_VARS.warning_message ) {
605                return CHARITABLE_RECURRING_VARS.warning_message;
606            }
607
608            // Fallback default message - check if offline should be included
609            var include_offline = ( typeof CHARITABLE_RECURRING_VARS !== 'undefined' &&
610                                   CHARITABLE_RECURRING_VARS.disable_offline_for_recurring );
611
612            if ( include_offline ) {
613                return 'Some payment methods (ACH, BECS, Cash App, and offline/check payments) are not available for recurring donations only. Please select a different payment method to continue.';
614            } else {
615                return 'Some payment methods (ACH, BECS, and Cash App) are not available for recurring donations only. Please select a different payment method to continue.';
616            }
617        }
618    }
619
620    return methods;
621
622})( jQuery );
623
624( function( $ ) {
625    $( 'body' ).on( 'charitable:form:initialize', function() {
626        CHARITABLE_RECURRING.init();
627    });
628})( 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.