1/** 2 * Frontend functionality for subscribers and tags. 3 * 4 * @since 1.9.6 5 * 6 * @package ConvertKit 7 * @author ConvertKit 8 */ 9 10/** 11 * Gets the subscriber ID for the given email address, storing 12 * it in the `ck_subscriber_id` cookie if it exists. 13 * 14 * Typically called when the user completes a ConvertKit Form 15 * that has either "Auto-confirm new subscribers" or 16 * "Send subscriber to thank you page" enabled (both scenarios 17 * include a ck_subscriber_id). 18 * 19 * @since 1.9.6 20 * 21 * @param string emailAddress Email Address 22 */ 23function convertStoreSubscriberEmailAsIDInCookie( emailAddress ) { 24 25 if ( convertkit.debug ) { 26 console.log( 'convertStoreSubscriberEmailAsIDInCookie' ); 27 console.log( emailAddress ); 28 } 29 30 fetch( 31 convertkit.ajaxurl, 32 { 33 method: 'POST', 34 headers: { 35 'Content-Type': 'application/x-www-form-urlencoded', 36 }, 37 body: new URLSearchParams( 38 { 39 action: 'convertkit_store_subscriber_email_as_id_in_cookie', 40 convertkit_nonce: convertkit.nonce, 41 email: emailAddress 42 } 43 ) 44 } 45 ) 46 .then( 47 function ( response ) { 48 if ( convertkit.debug ) { 49 console.log( response ); 50 } 51 52 return response.json(); 53 } 54 ) 55 .then( 56 function ( result ) { 57 if ( convertkit.debug ) { 58 console.log( result ); 59 } 60 61 // Emit custom event with subscriber ID. 62 convertKitEmitCustomEvent( 63 'convertkit_user_subscribed', 64 { 65 id: result.data.id, 66 email: emailAddress 67 } 68 ); 69 } 70 ) 71 .catch( 72 function ( error ) { 73 if ( convertkit.debug ) { 74 console.error( error ); 75 } 76 } 77 ); 78 79} 80 81/** 82 * Remove the url subscriber_id url param 83 * 84 * The 'ck_subscriber_id' should only be set on URLs included on 85 * links from a ConvertKit email with no other URL parameters. 86 * This function removes the parameters so a customer won't share 87 * a URL with their subscriber ID in it. 88 * 89 * @param url 90 */ 91function convertKitRemoveSubscriberIDFromURL( url ) { 92 93 // Parse URL. 94 const url_object = new URL( url ); 95 const ck_subscriber_id = url_object.searchParams.get( 'ck_subscriber_id' ); 96 97 // If ck_subscriber_id is null, it's not included in the URL. 98 // Don't modify the URL. 99 if ( ck_subscriber_id === null ) { 100 return; 101 } 102 103 // Remove ck_subscriber_id from URL params. 104 url_object.searchParams.delete( 'ck_subscriber_id' ); 105 106 // Get title and string of parameters. 107 const title = document.getElementsByTagName( 'title' )[0].innerHTML; 108 let params = url_object.searchParams.toString(); 109 110 // Only add '?' if there are parameters. 111 if ( params.length > 0 ) { 112 params = '?' + params; 113 } 114 115 // Update history. 116 window.history.replaceState( null, title, url_object.pathname + params + url_object.hash ); 117 118} 119 120/** 121 * Utility function to pause for the given number of milliseconds 122 * 123 * @since 1.9.6 124 * 125 * @param int milliseconds 126 */ 127function convertKitSleep( milliseconds ) { 128 129 var start = new Date().getTime(); 130 for (var i = 0; i < 1e7; i++) { 131 if ((new Date().getTime() - start) > milliseconds) { 132 break; 133 } 134 } 135 136} 137 138/** 139 * Emit a custom event with optional detail data. 140 * 141 * This function creates and dispatches a custom event with the specified 142 * event name and detail data. 143 * 144 * @since 2.5.0 145 * 146 * @param {string} eventName The name of the custom event to emit. 147 * @param {Object} [detail={}] Optional detail data to include with the event. 148 */ 149function convertKitEmitCustomEvent( eventName, detail ) { 150 151 const event = new CustomEvent( eventName, { detail } ); 152 document.dispatchEvent( event ); 153 154} 155 156/** 157 * Register events 158 */ 159document.addEventListener( 160 'DOMContentLoaded', 161 function () { 162 163 // Removes `ck_subscriber_id` from the URI. 164 convertKitRemoveSubscriberIDFromURL( window.location.href ); 165 166 // Store subscriber ID as a cookie from the email address used when a ConvertKit Form is submitted. 167 document.addEventListener( 168 'click', 169 function (e) { 170 // Check if the form submit button was clicked, or the span element was clicked and its parent is the form submit button. 171 if ( ! e.target.matches( '.formkit-submit' ) && ( ! e.target.parentElement || ! e.target.parentElement.matches( '.formkit-submit' ) ) ) { 172 if ( convertkit.debug ) { 173 console.log( 'not a ck form' ); 174 } 175 176 return; 177 } 178 179 // Get email address. 180 let emailAddress = document.querySelector( 'input[name="email_address"]' ).value; 181 182 // If the email address is empty, don't attempt to get the subscriber ID by email. 183 if ( ! emailAddress.length ) { 184 if ( convertkit.debug ) { 185 console.log( 'email empty' ); 186 } 187 188 return; 189 } 190
191 // If the email address is invalid, don't attempt to get the subscriber ID by email. 192 var validator = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 193 if ( ! validator.test( emailAddress.toLowerCase() ) ) { 194 if ( convertkit.debug ) { 195 console.log( 'email not an email address' ); 196 } 197 198 return; 199 } 200 201 // Wait a moment before sending the AJAX request. 202 convertKitSleep( 2000 ); 203 convertStoreSubscriberEmailAsIDInCookie( emailAddress ); 204 } 205 ); 206 207 } 208);
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.