Changeset 3429643
- Timestamp:
- 12/30/2025 01:34:29 PM (3 months ago)
- Location:
- otppal/trunk
- Files:
-
- 29 added
- 13 deleted
- 4 edited
-
assets/js/integrations/otppal-elementor-pro.js (modified) (8 diffs)
-
data (deleted)
-
includes/class-otppal-user-lookup.php (modified) (1 diff)
-
includes/data (added)
-
includes/data/country-dial-codes.php (added)
-
includes/integrations/cf7 (added)
-
includes/integrations/cf7/class-otppal-cf7.php (added)
-
includes/integrations/class-otppal-cf7.php (deleted)
-
includes/integrations/class-otppal-elementor-pro.php (deleted)
-
includes/integrations/class-otppal-fluent-forms.php (deleted)
-
includes/integrations/class-otppal-formidable-forms.php (deleted)
-
includes/integrations/class-otppal-gravity-forms.php (deleted)
-
includes/integrations/class-otppal-integrations.php (added)
-
includes/integrations/class-otppal-login.php (deleted)
-
includes/integrations/class-otppal-ninja-forms.php (deleted)
-
includes/integrations/class-otppal-signup.php (deleted)
-
includes/integrations/class-otppal-sureforms.php (deleted)
-
includes/integrations/class-otppal-wpforms.php (deleted)
-
includes/integrations/elementor (added)
-
includes/integrations/elementor/class-elementor-field-otppal-phone.php (added)
-
includes/integrations/elementor/class-elementor-field-otppal-verify.php (added)
-
includes/integrations/elementor/class-otppal-elementor-pro.php (added)
-
includes/integrations/fluent-forms (added)
-
includes/integrations/fluent-forms/class-fluentforms-field-otppal-phone.php (added)
-
includes/integrations/fluent-forms/class-fluentforms-field-otppal-verify.php (added)
-
includes/integrations/fluent-forms/class-otppal-fluent-forms.php (added)
-
includes/integrations/fluentforms (deleted)
-
includes/integrations/formidable (deleted)
-
includes/integrations/formidable-forms (added)
-
includes/integrations/formidable-forms/class-frm-field-otppal-phone.php (added)
-
includes/integrations/formidable-forms/class-frm-field-otppal-verify.php (added)
-
includes/integrations/formidable-forms/class-otppal-formidable-forms.php (added)
-
includes/integrations/formidable-forms/views (added)
-
includes/integrations/formidable-forms/views/field-otppal-verify-builder.php (added)
-
includes/integrations/gravity-forms (added)
-
includes/integrations/gravity-forms/class-otppal-gravity-forms.php (added)
-
includes/integrations/ninja-forms (added)
-
includes/integrations/ninja-forms/class-otppal-ninja-forms.php (added)
-
includes/integrations/sureforms (added)
-
includes/integrations/sureforms/class-otppal-sureforms.php (added)
-
includes/integrations/wp-auth (added)
-
includes/integrations/wp-auth/class-otppal-login.php (added)
-
includes/integrations/wp-auth/class-otppal-signup.php (added)
-
includes/integrations/wpforms/class-otppal-wpforms.php (added)
-
otppal.php (modified) (3 diffs)
-
readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
otppal/trunk/assets/js/integrations/otppal-elementor-pro.js
r3423725 r3429643 29 29 } 30 30 31 // Find the original input 31 // Check if this is a custom otppal_phone field (already has the container) 32 const $existingContainer = $field.find('.otppal-phone-field[data-otppal-phone-field="true"]'); 33 const $hiddenInput = $field.find('input.otppal-original-phone-input, input[type="hidden"]').first(); 34 35 if ($existingContainer.length > 0) { 36 // This is a custom otppal_phone field - initialize the existing container 37 const phoneFormat = $existingContainer.data('phone-format') || 38 (typeof otppalConfig !== 'undefined' ? otppalConfig.phoneFormat : 'international') || 39 'international'; 40 const defaultCountry = $existingContainer.data('default-country') || 41 (typeof otppalConfig !== 'undefined' ? otppalConfig.defaultCountry : 'US') || 42 'US'; 43 44 // Initialize phone input on existing container 45 const phoneInput = new OtpPalPhoneInput($existingContainer, { 46 format: phoneFormat, 47 defaultCountry: defaultCountry, 48 onValidate: function(valid, phone, error) { 49 // Update hidden input with formatted phone number 50 if ($hiddenInput.length > 0) { 51 if (valid) { 52 $hiddenInput.val(phone); 53 } else { 54 $hiddenInput.val(''); 55 } 56 } 57 } 58 }); 59 60 // Store reference 61 embeddedPhoneFields[formId] = phoneInput; 62 $field.data('otppal-initialized', true); 63 return; 64 } 65 66 // Legacy: Find the original input (for forms that use CSS classes on regular fields) 32 67 const $originalInput = $field.find('input[type="text"], input[type="tel"], input[type="email"], input[type="url"]').first(); 33 68 if ($originalInput.length === 0) { … … 97 132 98 133 /** 134 * Get phone number from tel field in form 135 */ 136 function getPhoneFromTelField($form) { 137 // Look for tel field (elementor-field-type-tel) 138 const $telField = $form.find('.elementor-field-type-tel input[type="tel"]'); 139 if ($telField.length > 0) { 140 const phoneValue = $telField.val(); 141 if (phoneValue && phoneValue.trim()) { 142 return phoneValue.trim(); 143 } 144 } 145 return null; 146 } 147 148 /** 99 149 * Check if form has OTP verification enabled 100 150 */ … … 105 155 } 106 156 107 // Check for embedded phone field 157 // Check for embedded phone field (by class) 108 158 if ($form.find('.elementor-field-group.otppal_phone').length > 0) { 159 return true; 160 } 161 162 // Fallback: Check for otppal_phone field type 163 if ($form.find('.elementor-field-type-otppal_phone').length > 0) { 109 164 return true; 110 165 } … … 131 186 } 132 187 133 // Remove our submit handlertemporarily to allow normal submission188 // Remove our handlers temporarily to allow normal submission 134 189 $form.off('submit.otppal'); 190 $form.find('button[type="submit"], input[type="submit"]').off('click.otppal'); 135 191 136 192 // Use a small delay to ensure lightbox is hidden before form submission 137 193 setTimeout(function() { 138 // Trigger Elementor's form submission194 // Get the submit button 139 195 const $submitButton = $form.find('button[type="submit"], input[type="submit"]'); 196 140 197 if ($submitButton.length) { 141 $submitButton.click(); 198 // Create a new click event that will trigger Elementor's handler 199 const clickEvent = new jQuery.Event('click', { 200 bubbles: true, 201 cancelable: true 202 }); 203 204 // Trigger the click event on the button 205 // This should trigger Elementor's form submission handler 206 $submitButton.trigger(clickEvent); 207 208 // If that doesn't work, try triggering submit directly 209 if (!clickEvent.isDefaultPrevented()) { 210 $form.trigger('submit'); 211 } 142 212 } else { 143 213 // Fallback: trigger submit event 144 $form. submit();214 $form.trigger('submit'); 145 215 } 146 216 … … 150 220 }, 2000); 151 221 }, 100); 222 } 223 224 // Hook into forms immediately, before Elementor initializes 225 function attachFormHandlers() { 226 // Find all Elementor forms and attach handlers directly 227 $('form.elementor-form').each(function() { 228 const $form = $(this); 229 230 // Skip if already processed 231 if ($form.data('otppal-handlers-attached')) { 232 return; 233 } 234 235 $form.data('otppal-handlers-attached', true); 236 237 // Attach click handler to submit button 238 $form.find('button[type="submit"], input[type="submit"]').on('click.otppal', function(e) { 239 const $button = $(this); 240 241 if (!isFormEnabled($form)) { 242 return; 243 } 244 if (isVerifying) { 245 return; 246 } 247 248 e.preventDefault(); 249 e.stopImmediatePropagation(); 250 currentForm = $form; 251 252 let phoneNumber = getEmbeddedPhoneNumber($form); 253 if (!phoneNumber) { 254 phoneNumber = getPhoneFromTelField($form); 255 } 256 257 if (phoneNumber) { 258 lightbox.show(phoneNumber); 259 } else { 260 lightbox.show(); 261 } 262 263 return false; 264 }); 265 266 // Attach submit handler directly to form 267 $form.on('submit.otppal', function(e) { 268 if (!isFormEnabled($form)) { 269 return; 270 } 271 if (isVerifying) { 272 return; 273 } 274 275 e.preventDefault(); 276 e.stopImmediatePropagation(); 277 currentForm = $form; 278 279 let phoneNumber = getEmbeddedPhoneNumber($form); 280 if (!phoneNumber) { 281 phoneNumber = getPhoneFromTelField($form); 282 } 283 284 if (phoneNumber) { 285 lightbox.show(phoneNumber); 286 } else { 287 lightbox.show(); 288 } 289 290 return false; 291 }); 292 }); 152 293 } 153 294 … … 188 329 $hiddenInput.val(phone); 189 330 } 331 332 // Also update the otppal_phone field's hidden input if it exists 333 const $phoneField = currentForm.find('.elementor-field-group.otppal_phone'); 334 if ($phoneField.length > 0) { 335 const $phoneHiddenInput = $phoneField.find('input.otppal-original-phone-input, input[type="hidden"]').first(); 336 if ($phoneHiddenInput.length > 0) { 337 $phoneHiddenInput.val(phone); 338 } 339 } 190 340 } 191 341 … … 200 350 // Initialize embedded phone fields 201 351 initializeEmbeddedPhoneFields(); 352 353 // Attach form handlers immediately 354 attachFormHandlers(); 202 355 203 356 // Re-initialize when Elementor forms are loaded dynamically 204 357 $(document).on('elementor/popup/show', function() { 205 setTimeout(initializeEmbeddedPhoneFields, 100); 358 setTimeout(function() { 359 initializeEmbeddedPhoneFields(); 360 attachFormHandlers(); 361 }, 100); 206 362 }); 207 363 208 364 // Also listen for Elementor's form render event 209 365 $(document).on('elementor/frontend/init', function() { 210 setTimeout(initializeEmbeddedPhoneFields, 100); 211 }); 366 setTimeout(function() { 367 initializeEmbeddedPhoneFields(); 368 attachFormHandlers(); 369 }, 100); 370 }); 371 372 // Also watch for dynamically added forms 373 if (typeof MutationObserver !== 'undefined') { 374 const observer = new MutationObserver(function(mutations) { 375 attachFormHandlers(); 376 }); 377 observer.observe(document.body, { 378 childList: true, 379 subtree: true 380 }); 381 } 212 382 213 383 /** 214 * Intercept Elementor Pro form submission 384 * Intercept Elementor Pro form button click 385 * This runs before the submit event, so we can intercept before Elementor's handler 386 */ 387 $(document).on('click.otppal', 'form.elementor-form button[type="submit"], form.elementor-form input[type="submit"]', function(e) { 388 const $button = $(this); 389 const $form = $button.closest('form.elementor-form'); 390 391 // Check if OTP is enabled for this form 392 if (!isFormEnabled($form)) { 393 return; // Let form submit normally 394 } 395 396 // Don't intercept if we're already verifying or form is being submitted after verification 397 if (isVerifying) { 398 return; // Let form submit normally 399 } 400 401 // Prevent default submission 402 e.preventDefault(); 403 e.stopImmediatePropagation(); 404 405 // Store form data 406 currentForm = $form; 407 408 // Try to get phone number from embedded phone field first 409 let phoneNumber = getEmbeddedPhoneNumber($form); 410 411 // If no embedded phone field, try to get from tel field 412 if (!phoneNumber) { 413 phoneNumber = getPhoneFromTelField($form); 414 } 415 416 if (phoneNumber) { 417 // Form has phone number - show modal in loading state and request OTP 418 lightbox.show(phoneNumber); 419 } else { 420 // No phone number found - show modal with phone input 421 lightbox.show(); 422 } 423 424 return false; // Additional safety 425 }); 426 427 /** 428 * Also intercept form submit event as backup 429 * This uses stopImmediatePropagation to prevent Elementor's handler from running 215 430 */ 216 431 $(document).on('submit.otppal', 'form.elementor-form', function(e) { … … 226 441 return; // Let form submit normally 227 442 } 228 229 // Prevent default submission 443 444 // Prevent default submission - this must happen BEFORE Elementor's handler 230 445 e.preventDefault(); 231 e.stop Propagation();446 e.stopImmediatePropagation(); // Stop other handlers from running 232 447 233 448 // Store form data 234 449 currentForm = $form; 235 450 236 // Check if form has embedded phone field 237 const embeddedPhone = getEmbeddedPhoneNumber($form); 238 if (embeddedPhone) { 239 // Form has embedded phone field - show modal in loading state and request OTP 240 lightbox.show(embeddedPhone); 451 // Try to get phone number from embedded phone field first 452 let phoneNumber = getEmbeddedPhoneNumber($form); 453 454 // If no embedded phone field, try to get from tel field 455 if (!phoneNumber) { 456 phoneNumber = getPhoneFromTelField($form); 457 } 458 459 if (phoneNumber) { 460 // Form has phone number - show modal in loading state and request OTP 461 lightbox.show(phoneNumber); 241 462 } else { 242 // No embedded phone field - show modal with phone input463 // No phone number found - show modal with phone input 243 464 lightbox.show(); 244 465 } 466 467 return false; // Additional safety 245 468 }); 246 469 -
otppal/trunk/includes/class-otppal-user-lookup.php
r3427655 r3429643 46 46 // Load country codes file if not already loaded 47 47 if (self::$country_dial_codes === null) { 48 $codes_file = OTPPAL_PATH . ' data/country-dial-codes.php';48 $codes_file = OTPPAL_PATH . 'includes/data/country-dial-codes.php'; 49 49 if (file_exists($codes_file)) { 50 50 self::$country_dial_codes = require $codes_file; -
otppal/trunk/otppal.php
r3427662 r3429643 19 19 } 20 20 21 // Suppress all error output during activation to prevent "headers already sent" errors 22 // This is a workaround for ACF/Polylang bugs where they output notices during plugin activation 23 if (isset($_GET['action']) && $_GET['action'] === 'activate' && isset($_GET['plugin'])) { 24 $plugin = sanitize_text_field($_GET['plugin']); 25 if (strpos($plugin, 'otppal') !== false) { 26 // Suppress all error output 27 @ini_set('display_errors', 0); 28 @ini_set('display_startup_errors', 0); 29 error_reporting(0); 30 31 // Also start output buffering as backup 32 if (ob_get_level() === 0) { 33 ob_start(); 34 register_shutdown_function(function () { 35 if (ob_get_level() > 0) { 36 ob_end_clean(); 37 } 38 }); 39 } 40 } 41 } 42 21 43 // Define plugin constants 22 44 if (!defined('OTPPAL_VERSION')) { 23 define('OTPPAL_VERSION', '2. 3.9');45 define('OTPPAL_VERSION', '2.4.0'); 24 46 } 25 47 if (!defined('OTPPAL_PATH')) { … … 32 54 define('OTPPAL_BASENAME', plugin_basename(__FILE__)); 33 55 } 34 35 // Server URL - hardcoded (from docker-compose.yml: wordpress service port 8000:80)36 56 if (!defined('OTPPAL_SERVER_URL')) { 37 define('OTPPAL_SERVER_URL', 'http ://localhost:8000');57 define('OTPPAL_SERVER_URL', 'https://otppal.com'); 38 58 } 39 59 … … 77 97 require_once OTPPAL_PATH . 'includes/class-otppal-user-lookup.php'; 78 98 79 // Load form integrations 80 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-cf7.php'; 81 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-gravity-forms.php'; 82 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-wpforms.php'; 83 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-fluent-forms.php'; 84 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-ninja-forms.php'; 85 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-formidable-forms.php'; 86 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-sureforms.php'; 87 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-elementor-pro.php'; 88 89 // Initialize form integrations (each concrete class checks if its plugin is active) 90 OtpPal_CF7::get_instance(); 91 OtpPal_Gravity_Forms::get_instance(); 92 OtpPal_WPForms::get_instance(); 93 OtpPal_Fluent_Forms::get_instance(); 94 OtpPal_Ninja_Forms::get_instance(); 95 OtpPal_Formidable_Forms::get_instance(); 96 OtpPal_SureForms::get_instance(); 97 OtpPal_Elementor_Pro::get_instance(); 99 // Load and initialize all form integrations via boot file 100 require_once OTPPAL_PATH . 'includes/integrations/class-otppal-integrations.php'; 98 101 99 102 // Load login integration 100 require_once OTPPAL_PATH . 'includes/integrations/ class-otppal-login.php';103 require_once OTPPAL_PATH . 'includes/integrations/wp-auth/class-otppal-login.php'; 101 104 OtpPal_Login::get_instance(); 102 105 103 106 // Load sign-up integration (only if OTP login is enabled) 104 107 if (get_option('otppal_enable_otp_login', '0') === '1') { 105 require_once OTPPAL_PATH . 'includes/integrations/ class-otppal-signup.php';108 require_once OTPPAL_PATH . 'includes/integrations/wp-auth/class-otppal-signup.php'; 106 109 OtpPal_Signup::get_instance(); 107 110 } -
otppal/trunk/readme.txt
r3428524 r3429643 6 6 Tested up to: 6.9 7 7 Requires PHP: 7.4 8 Stable tag: 2. 3.98 Stable tag: 2.4.0 9 9 License: GPL2 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 105 105 106 106 == Changelog == 107 = 2.4.0 = 108 * Elementor pro integration 109 * Fix plugin activation issue 110 * Improve plugin structure 111 107 112 = 2.3.9 = 108 113 * Enhanced phone number lookup to support both billing and shipping phone fields … … 165 170 166 171 == Upgrade Notice == 172 = 2.4.0 = 173 Full support for Elementor pro forms, better stability. 174 167 175 = 2.3.9 = 168 176 Enhanced phone number matching and improved error handling in OTP verification flow.
Note: See TracChangeset
for help on using the changeset viewer.