# Tracking System Architecture ## Overview The tracking system provides comprehensive analytics for user interactions across onboarding, settings, and other flows. It features source-based field filtering, multi-funnel support, and extensible adapter architecture to prevent tracking loops and enable granular event control. It monitors WordPress data stores rather than adding code to frontend components, ensuring comprehensive coverage of all state changes regardless of their source (user actions, API responses, system updates) while maintaining clean separation of concerns. ## File Organization ``` src/ ├── services/ │ └── tracking/ │ ├── registry.js # Central funnel registration │ ├── subscription-manager.js # Store subscription management │ ├── utils/ │ │ ├── field-config-helpers.js # Field config helpers & utilities │ │ └── utils.js # Core tracking utilities │ ├── services/ │ │ └── funnel-tracking.js # Funnel tracking service │ ├── adapters/ # Tracking destination adapters │ │ ├── woocommerce-tracks.js # WooCommerce Tracks integration │ │ └── console-logger.js # Console output │ ├── funnels/ # Funnel-specific configurations │ │ └── onboarding.js # Onboarding funnel config & translations │ ├── index.js # Main exports │ └── init.js # Initialization system ├── data/ # Redux stores │ ├── tracking/ # Dedicated tracking store │ │ ├── actions.js # Field source tracking actions │ │ ├── reducer.js # Field source state management │ │ ├── selectors.js # Field source data access │ │ └── index.js # Store initialization │ ├── onboarding/ # Clean business logic store │ │ ├── actions.js # Pure business actions │ │ ├── reducer.js # Clean business logic │ │ ├── selectors.js # Business data access │ │ └── hooks.js # Enhanced hooks with tracking │ ├── common/ # Clean business logic store │ │ ├── actions.js # Pure business actions │ │ ├── reducer.js # Clean business logic │ │ ├── selectors.js # Business data access │ │ └── hooks.js # Enhanced hooks with tracking │ └── utils.js # Enhanced createHooksForStore └── components/ # Enhanced to pass tracking sources └── **/*.js # Form components updated with source attribution ``` ## 1. Registry System (`registry.js`) Manages funnel registration and coordinates multiple tracking concerns without conflicts. ### Store-to-Funnel Mapping ```javascript // Registry maintains mapping of stores to multiple funnels const trackingRegistry = { funnels: {}, storeToFunnel: {}, // Store name -> array of funnel IDs instances: {}, }; // Example mapping: { 'wc/paypal/onboarding': ['ppcp_onboarding', 'settings_funnel'], 'wc/paypal/common': ['ppcp_onboarding', 'other_funnel'], } ``` ### Usage ```javascript import { registerFunnel } from '../services/tracking/registry'; registerFunnel('ppcp_onboarding', onboardingConfig); ``` ## 2. Subscription Manager (`subscription-manager.js`) Creates **unified subscriptions** to WordPress data stores and routes changes to **multiple relevant funnels**. ### Single Subscription, Multiple Funnels ```javascript class SubscriptionManager { constructor() { this.storeSubscriptions = {}; // ONE subscription per store this.storeRegistrations = {}; // MULTIPLE funnel registrations per store } ensureStoreSubscription(storeName) { if (this.storeSubscriptions[storeName]) { return; // Skip if subscription already exists } // Create unified subscription for all funnels tracking this store const unsubscribe = wp.data.subscribe(() => { this.handleStoreChange(storeName); }); } } ``` ### Benefits - **One subscription per store** regardless of funnel count - **Independent funnel logic** - each has its own rules and conditions - **Isolated state** - each funnel tracks its own previous values ## 3. Tracking Store (`data/tracking/`) Separate Redux store handles all field source information. ### State Structure ```javascript // { storeName: { fieldName: { source, timestamp } } } { 'wc/paypal/onboarding': { 'step': { source: 'user', timestamp: 1638360000000 }, 'isCasualSeller': { source: 'user', timestamp: 1638360000000 } }, 'wc/paypal/common': { 'useSandbox': { source: 'system', timestamp: 1638360000000 } } } ``` ## 4. Universal Hook System (`data/utils.js`) `createHooksForStore` makes **any Redux store** tracking-compatible. ```javascript // Works with ANY store const { usePersistent, useTransient } = createHooksForStore('wc/paypal/any-store'); // In components const [ field, setField ] = usePersistent('fieldName'); setField(newValue, 'user'); // Automatically tracked if configured ``` ## 5. Source-Based Field Filtering Field-level rules define which change sources trigger tracking events. ```javascript // Configuration fieldRules: { step: { allowedSources: ['user', 'system'] }, // Track all changes isCasualSeller: { allowedSources: ['user'] }, // Only user changes } // Usage setIsCasualSeller(true, 'user'); // Tracked setIsCasualSeller(false); // Filtered out (no source) ``` **Source Types:** - `'user'` - Direct user interactions - `'system'` - System-initiated changes ## 6. Funnel Configuration Uses `FunnelConfigBuilder` pattern: ```javascript // src/services/tracking/funnels/onboarding.js export const config = FunnelConfigBuilder.createBasicFunnel(FUNNEL_ID, { debug: false, adapters: ['woocommerce-tracks'], eventPrefix: 'ppcp_onboarding', trackingCondition: { store: 'wc/paypal/common', selector: 'merchant', field: 'isConnected', expectedValue: false } }) .addEvents(EVENTS) .addTranslations(TRANSLATIONS) .addStore('wc/paypal/onboarding', [ createFieldTrackingConfig('step', 'persistent', { rules: { allowedSources: ['user', 'system'] } }) ]) .build(); ``` ## 7. Initialization (`init.js`) Required before store registration: ```javascript import { registerFunnel } from './registry'; export function initializeTrackingFunnels() { if (initialized) return; registerFunnel(ONBOARDING_FUNNEL_ID, onboardingConfig); initialized = true; } // Auto-initialize initializeTrackingFunnels(); ``` ## 8. Store Registration Stores register with funnels in their index files: ```javascript // src/data/onboarding/index.js import { addStoreToFunnel } from '../../services/tracking'; export const initStore = () => { const store = createReduxStore(STORE_NAME, { reducer, actions, selectors }); register(store); addStoreToFunnel(STORE_NAME, ONBOARDING_FUNNEL_ID); return Boolean(wp.data.select(STORE_NAME)); }; ``` ## Adding Tracking to New Stores ### 1. Create Clean Business Store ```javascript // actions.js export const setPersistent = (prop, value) => ({ type: ACTION_TYPES.SET_PERSISTENT, payload: { [prop]: value }, }); // reducer.js const reducer = createReducer(defaultTransient, defaultPersistent, { [ACTION_TYPES.SET_PERSISTENT]: (state, payload) => changePersistent(state, payload), }); ``` ### 2. Create Tracking-Enabled Hooks ```javascript // hooks.js import { createHooksForStore } from '../utils'; export const { usePersistent, useTransient } = createHooksForStore('wc/paypal/your-store'); ``` ### 3. Register Store ```javascript // index.js addStoreToFunnel(STORE_NAME, 'your-funnel-id'); ``` ### 4. Configure Funnel ```javascript // funnels/your-funnel.js export const config = FunnelConfigBuilder.createBasicFunnel('your-funnel', { debug: false, adapters: ['console'], }) .addStore('wc/paypal/your-store', [ createFieldTrackingConfig('yourField', 'persistent', { rules: { allowedSources: ['user'] } }) ]) .addTranslations({ yourField: (oldValue, newValue, metadata, trackingService) => { trackingService.sendToAdapters('your_event_name', { new_value: newValue, old_value: oldValue }); } }) .build(); ``` ## Multi-Funnel Example Multiple funnels tracking the same store: ```javascript // Both register interest in same store addStoreToFunnel('wc/paypal/onboarding', 'ppcp_onboarding'); addStoreToFunnel('wc/paypal/onboarding', 'settings_funnel'); // Results in ONE subscription, TWO registrations with different rules: storeRegistrations = { 'wc/paypal/onboarding': [ { funnelId: 'ppcp_onboarding', fieldRules: { step: {allowedSources: ['user', 'system']} }, trackingCondition: { field: 'isConnected', expectedValue: false }, previousValues: {} // Separate per funnel }, { funnelId: 'settings_funnel', fieldRules: { step: {allowedSources: ['user']} }, trackingCondition: { field: 'isConnected', expectedValue: true }, previousValues: {} // Separate per funnel } ] } ``` ## Debugging ### Enable Debug Mode ```javascript export const config = FunnelConfigBuilder.createBasicFunnel('funnel', { debug: true, }); ``` ### Inspect Tracking Store ```javascript const trackingStore = wp.data.select('wc/paypal/tracking'); console.log('All sources:', trackingStore.getAllFieldSources()); console.log('Store sources:', trackingStore.getStoreFieldSources('wc/paypal/onboarding')); ``` ### Check Registry Status ```javascript import { getTrackingStatus, getMultiFunnelStores } from '../services/tracking'; console.log('Status:', getTrackingStatus()); console.log('Multi-funnel stores:', getMultiFunnelStores()); ``` ## Event Schema Events follow pattern: `ppcp_{funnel}_{action}_{object}` Examples: - `ppcp_onboarding_account_type_select` - `ppcp_onboarding_step_forward` - `ppcp_settings_payment_method_toggle`
تصویر کتاب

کتاب داستان‌ها

مجموعه‌ای نفیس از لحظاتی در گذر زمان، شامل عکس‌هایی از لویی فکنشتاین، پل استرند و آساهاچی کونو.

هم‌اکنون برای پیش‌سفارش در دسترس است.

(()=>{var t={31:(t,e,a)=>{var o=a(456),n=jQuery,i=function(){var t=this;this.params=[],this.modal=new o,this.modal.onStop=function(e){t.onStop(e)}};i.prototype.setParams=function(t){this.params=Ai1wm.Util.list(t)},i.prototype.start=function(t,e){var a=this;if(0===(e=e||0)&&this.stopExport(!1),!this.isExportStopped()){n(window).on("beforeunload",function(){return ai1wmke_locale.stop_resetting_your_website}),this.setStatus({type:"info",message:ai1wm_locale.preparing_to_export});var o=this.params.concat({name:"secret_key",value:ai1wm_export.secret_key});t&&(o=o.concat(Ai1wm.Util.list(t))),n.ajax({url:ai1wm_export.ajax.url,type:"POST",dataType:"json",data:o,dataFilter:function(t){return Ai1wm.Util.json(t)}}).done(function(){a.getStatus()}).done(function(t){t&&a.run(t)}).fail(function(n){var i=1e3*e;try{var r=Ai1wm.Util.json(n.responseText);if(r){var s=JSON.parse(r).errors.pop();if(s.message)return a.stopExport(!0),void a.setStatus({type:"error",title:ai1wm_locale.unable_to_export,message:s.message,nonce:Ai1wm.Util.findValueByName(o,"storage")})}}catch(t){}if(e>=5)return a.stopExport(!0),void a.setStatus({type:"error",title:ai1wm_locale.unable_to_export,message:ai1wm_locale.unable_to_start_the_export,nonce:Ai1wm.Util.findValueByName(o,"storage")});e++,setTimeout(a.start.bind(a,t,e),i)})}},i.prototype.run=function(t,e){var a=this;e=e||0,this.isExportStopped()||n.ajax({url:ai1wm_export.ajax.url,type:"POST",dataType:"json",data:t,dataFilter:function(t){return Ai1wm.Util.json(t)}}).done(function(t){t&&a.run(t)}).fail(function(o){var n=1e3*e;try{var i=Ai1wm.Util.json(o.responseText);if(i){var r=JSON.parse(i).errors.pop();if(r.message)return a.stopExport(!0),void a.setStatus({type:"error",title:ai1wm_locale.unable_to_export,message:r.message,nonce:Ai1wm.Util.findValueByName(t,"storage")})}}catch(t){}if(e>=5)return a.stopExport(!0),void a.setStatus({type:"error",title:ai1wm_locale.unable_to_export,message:ai1wm_locale.unable_to_run_the_export,nonce:Ai1wm.Util.findValueByName(t,"storage")});e++,setTimeout(a.run.bind(a,t,e),n)})},i.prototype.clean=function(t,e){var a=this;0===(e=e||0)&&this.stopExport(!0),this.setStatus({type:"info",message:ai1wm_locale.please_wait_stopping_the_export});var o=this.params.concat({name:"secret_key",value:ai1wm_export.secret_key}).concat({name:"priority",value:300}).concat({name:"ai1wm_export_cancel",value:1});t&&(o=o.concat(Ai1wm.Util.list(t))),n.ajax({url:ai1wm_export.ajax.url,type:"POST",dataType:"json",data:o,dataFilter:function(t){return Ai1wm.Util.json(t)}}).done(function(){n(window).off("beforeunload"),a.modal.destroy()}).fail(function(n){var i=1e3*e;try{var r=Ai1wm.Util.json(n.responseText);if(r){var s=JSON.parse(r).errors.pop();if(s.message)return a.stopExport(!0),void a.setStatus({type:"error",title:ai1wm_locale.unable_to_export,message:s.message,nonce:Ai1wm.Util.findValueByName(o,"storage")})}}catch(t){}if(e>=5)return a.stopExport(!0),void a.setStatus({type:"error",title:ai1wm_locale.unable_to_export,message:ai1wm_locale.unable_to_stop_the_export,nonce:Ai1wm.Util.findValueByName(o,"storage")});e++,setTimeout(a.clean.bind(a,t,e),i)})},i.prototype.getStatus=function(){var t=this;this.isExportStopped()||(this.statusXhr=n.ajax({url:ai1wm_export.status.url,type:"GET",dataType:"json",cache:!1,dataFilter:function(t){return Ai1wm.Util.json(t)}}).done(function(e){if(e)switch(t.setStatus(e),e.type){case"done":case"error":case"download":return void n(window).off("beforeunload")}setTimeout(t.getStatus.bind(t),3e3)}).fail(function(){setTimeout(t.getStatus.bind(t),3e3)}))},i.prototype.setStatus=function(t){this.modal.render(t)},i.prototype.onStop=function(t){this.clean(t)},i.prototype.stopExport=function(t){try{t&&this.statusXhr&&this.statusXhr.abort()}finally{this.isStopped=t}},i.prototype.isExportStopped=function(){return this.isStopped},t.exports=i},213:function(t,e,a){var o,n,i;n=[],void 0===(i="function"==typeof(o=function(){"use strict";function e(t,e){return void 0===e?e={autoBom:!1}:"object"!=typeof e&&(console.warn("Deprecated: Expected third argument to be a object"),e={autoBom:!e}),e.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(t.type)?new Blob(["\ufeff",t],{type:t.type}):t}function o(t,e,a){var o=new XMLHttpRequest;o.open("GET",t),o.responseType="blob",o.onload=function(){p(o.response,e,a)},o.onerror=function(){console.error("could not download file")},o.send()}function n(t){var e=new XMLHttpRequest;e.open("HEAD",t,!1);try{e.send()}catch(t){}return 200<=e.status&&299>=e.status}function i(t){try{t.dispatchEvent(new MouseEvent("click"))}catch(a){var e=document.createEvent("MouseEvents");e.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),t.dispatchEvent(e)}}var r="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof a.g&&a.g.global===a.g?a.g:void 0,s=r.navigator&&/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),p=r.saveAs||("object"!=typeof window||window!==r?function(){}:"download"in HTMLAnchorElement.prototype&&!s?function(t,e,a){var s=r.URL||r.webkitURL,p=document.createElement("a");e=e||t.name||"download",p.download=e,p.rel="noopener","string"==typeof t?(p.href=t,p.origin===location.origin?i(p):n(p.href)?o(t,e,a):i(p,p.target="_blank")):(p.href=s.createObjectURL(t),setTimeout(function(){s.revokeObjectURL(p.href)},4e4),setTimeout(function(){i(p)},0))}:"msSaveOrOpenBlob"in navigator?function(t,a,r){if(a=a||t.name||"download","string"!=typeof t)navigator.msSaveOrOpenBlob(e(t,r),a);else if(n(t))o(t,a,r);else{var s=document.createElement("a");s.href=t,s.target="_blank",setTimeout(function(){i(s)})}}:function(t,e,a,n){if((n=n||open("","_blank"))&&(n.document.title=n.document.body.innerText="downloading..."),"string"==typeof t)return o(t,e,a);var i="application/octet-stream"===t.type,p=/constructor/i.test(r.HTMLElement)||r.safari,l=/CriOS\/[\d]+/.test(navigator.userAgent);if((l||i&&p||s)&&"undefined"!=typeof FileReader){var c=new FileReader;c.onloadend=function(){var t=c.result;t=l?t:t.replace(/^data:[^;]*;/,"data:attachment/file;"),n?n.location.href=t:location=t,n=null},c.readAsDataURL(t)}else{var u=r.URL||r.webkitURL,d=u.createObjectURL(t);n?n.location=d:location.href=d,n=null,setTimeout(function(){u.revokeObjectURL(d)},4e4)}});r.saveAs=p.saveAs=p,t.exports=p})?o.apply(e,n):o)||(t.exports=i)},456:t=>{var e=jQuery,a=function(){var t=this;this.error=function(a){var o=e("
"),n=e("
"),i=e("

"),r=e("

").html(a.message),s=e("
"),p=e("").addClass("ai1wm-title-red").text(a.title),l=e('').on("click",function(){t.destroy()});if(l.append(ai1wm_locale.close_export),s.append(l),i.append(p),n.append(i).append(r),a.nonce){var c=e('');c.text(ai1wm_locale.view_error_log_button),c.prop("href",ai1wm_export.storage.url+"/"+ai1wm_export.error_log.pattern.replace("%s",a.nonce)),n.append(e("
").append(c))}o.append(n).append(s),t.modal.html(o).show(),t.modal.trigger("focus"),t.overlay.show()},this.info=function(a){var o=e("
"),n=e("
"),i=e("

"),r=e("

").html(a.message),s=e("
"),p=e(''),l=e('').on("click",function(){l.attr("disabled","disabled"),t.onStop()});l.append(' '+ai1wm_locale.stop_export),s.append(l),i.append(p),n.append(i).append(r),o.append(n).append(s),t.modal.html(o).show(),t.modal.trigger("focus"),t.overlay.show()},this.done=function(a){var o=e("
"),n=e("
"),i=e("

"),r=e("

").html(a.message),s=e("
"),p=e("").addClass("ai1wm-title-green").text(a.title),l=e('').on("click",function(){t.destroy()});l.append(ai1wm_locale.close_export),s.append(l),i.append(p),n.append(i).append(r),o.append(n).append(s),t.modal.html(o).show(),t.modal.trigger("focus"),t.overlay.show()},this.download=function(a){var o=e("
"),n=e("
"),i=e("

").html(a.message),r=e("
"),s=e('').on("click",function(){t.destroy()}),p=e(".ai1wm-menu-count");p.text(+p.text()+1),p.text()>1?p.prop("title",ai1wm_locale.backups_count_plural.replace("%d",p.text())):(p.removeClass("ai1wm-menu-hide"),p.prop("title",ai1wm_locale.backups_count_singular.replace("%d",p.text()))),s.append(ai1wm_locale.close_export),r.append(s),n.append(i),o.append(n).append(r),t.modal.html(o).show(),t.modal.trigger("focus"),t.overlay.show()},this.overlay=e('
'),this.modal=e(''),e("body").append(this.overlay).append(this.modal)};a.prototype.render=function(t){switch(e(document).trigger("ai1wm-export-status",t),t.type){case"error":this.error(t);break;case"info":this.info(t);break;case"done":this.done(t);break;case"download":this.download(t)}},a.prototype.destroy=function(){this.modal.hide(),this.overlay.hide()},t.exports=a},647:()=>{var t;(t=jQuery).fn.ai1wm_find_replace=function(){return t(this).on("click",function(e){e.preventDefault();var a=t("#ai1wm-queries > li:first").clone();a.find("input").val(""),a.find(".ai1wm-query-find-text").html("<text>"),a.find(".ai1wm-query-replace-text").html("<another-text>"),t("#ai1wm-queries > li").removeClass("ai1wm-open"),t(a).addClass("ai1wm-open"),t("#ai1wm-queries").append(a),t(a).ai1wm_query(),t(a).find("p:first").on("click",function(){t(this).parent().toggleClass("ai1wm-open")})}),this}},705:()=>{var t;(t=jQuery).fn.ai1wm_query=function(){var e=t(this).find("input.ai1wm-query-find-input"),a=t(this).find("input.ai1wm-query-replace-input"),o=t(this).find("small.ai1wm-query-find-text"),n=t(this).find("small.ai1wm-query-replace-text");return e.on("change paste input keypress keydown keyup",function(){var e=t(this).val().length>0?t(this).val():"";o.text(e)}),a.on("change paste input keypress keydown keyup",function(){var e=t(this).val().length>0?t(this).val():"";n.text(e)}),this}}},e={};function a(o){var n=e[o];if(void 0!==n)return n.exports;var i=e[o]={exports:{}};return t[o].call(i.exports,i,i.exports,a),i.exports}a.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return a.d(e,{a:e}),e},a.d=(t,e)=>{for(var o in e)a.o(e,o)&&!a.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},a.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),a.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=a(213),e=a(705),o=a(647),n=a(31);jQuery(document).ready(function(e){var a=new n;e("#ai1wm-export-file").on("click",function(t){if(e("#ai1wm-encrypt-backups").is(":checked")){var o=e("#ai1wm-backup-encrypt-password"),n=e("#ai1wm-backup-encrypt-password-confirmation");if(!o.val().length)return o.parent().addClass("ai1wm-has-error"),o.focus(),!1;if(o.val()!==n.val())return n.parent().addClass("ai1wm-has-error"),n.focus(),!1}var i=Ai1wm.Util.random(12),r=Ai1wm.Util.form("#ai1wm-export-form").concat({name:"storage",value:i}).concat({name:"file",value:1});a.setParams(r),a.start(),t.preventDefault()}),e(document).on("click",".ai1wm-modal-container .ai1wm-direct-download",function(a){a.preventDefault();var o=e(this).prop("download"),n={secret_key:ai1wm_export.secret_key,archive:o},i=new XMLHttpRequest;i.addEventListener("readystatechange",function(){2===i.readyState&&200===i.status||3===i.readyState||4===i.readyState&&(i.status<400?(0,t.saveAs)(i.response,Ai1wm.Util.basename(o)):alert(ai1wm_locale.archive_browser_download_error))}),i.responseType="blob";var r=new FormData;for(var s in n)r.append(s,n[s]);i.open("post",ai1wm_export.download.url),i.send(r)}),e(".ai1wm-accordion > .ai1wm-title").on("click",function(){e(this).parent().toggleClass("ai1wm-active")}),e("#ai1wm-add-new-replace-button").ai1wm_find_replace(),e(".ai1wm-expandable > p:first, .ai1wm-expandable > h4:first, .ai1wm-expandable > div.ai1wm-button-main").on("click",function(){e(this).parent().toggleClass("ai1wm-open")}),e(".ai1wm-query").ai1wm_query(),e(".ai1wm-toggle-password-visibility").on("click",function(){return e(this).toggleClass("ai1wm-icon-eye ai1wm-icon-eye-blocked"),e(this).prev().prop("type",function(t,e){return"text"===e?"password":"text"}),!1}),e("#ai1wm-encrypt-backups").on("click",function(){e(".ai1wm-encrypt-backups-passwords-toggle").toggle()}),e("#ai1wm-backup-encrypt-password").on("keyup",function(){var t=e(this),a=e("#ai1wm-backup-encrypt-password-confirmation");t.val()!==a.val()&&a.parent().addClass("ai1wm-has-error"),t.val().length&&t.parent().removeClass("ai1wm-has-error")}),e("#ai1wm-backup-encrypt-password-confirmation").on("keyup",function(){var t=e(this);e("#ai1wm-backup-encrypt-password").val()!==t.val()?t.parent().addClass("ai1wm-has-error"):t.parent().removeClass("ai1wm-has-error")})}),a.g.Ai1wm=jQuery.extend({},a.g.Ai1wm,{Query:e,FindReplace:o,Export:n})})()})(); https://ipasexpo.com/wp-sitemap-posts-post-1.xmlhttps://ipasexpo.com/wp-sitemap-posts-page-1.xmlhttps://ipasexpo.com/wp-sitemap-posts-el_events-1.xmlhttps://ipasexpo.com/wp-sitemap-taxonomies-category-1.xmlhttps://ipasexpo.com/wp-sitemap-taxonomies-post_tag-1.xmlhttps://ipasexpo.com/wp-sitemap-users-1.xml